106

I'm writing a bash script to get some podcasts. The problem is that some of the podcast numbers are one digits while others are two/three digits, therefore I need to pad them to make them all 3 digits.

I tried the following:

n=1 n = printf %03d $n wget http://aolradio.podcast.aol.com/sn/SN-$n.mp3 

but the variable 'n' doesn't stay padded permanently. How can I make it permanent?

0

8 Answers 8

145

Use command substitution to assign the result of the printf command:

n=1 wget http://aolradio.podcast.aol.com/sn/SN-$(printf %03d $n).mp3 

EDIT: Note that I removed one line which was not really necessary. If you want to assign the output of 'printf %...' to n, you could use

n=$(printf %03d $n) 

and after that, use the $n variable substitution you used before.

Sign up to request clarification or add additional context in comments.

2 Comments

Why not: wget $(printf http://aolradio.podcast.aol.com/sn/SN-%03d $n.mp3, $n). Just put the whole URL in the printf statement.
What if you actually need to pad a string? for example, I have the string "Hello" but I need to always print 10 characters, I would need to print the string: "-----Hello" or if I have "yes" I still get 10 characters printed as: "-------yes"
54

Seems you're assigning the return value of the printf command (which is its exit code), you want to assign the output of printf.

bash-3.2$ n=1 bash-3.2$ n=$(printf %03d $n) bash-3.2$ echo $n 001 

2 Comments

Why is $() preferable?
@bli It can be nested, whereas backticks cannot (at least not without some form of escaping)
25

Attention though if your input string has a leading zero!
printf will still do the padding, but also convert your string to hex octal format.

# looks ok $ echo `printf "%05d" 03` 00003 # but not for numbers over 8 $ echo `printf "%05d" 033` 00027 

A solution to this seems to be printing a float instead of decimal.
The trick is omitting the decimal places with .0f.

# works with leading zero $ echo `printf "%05.0f" 033` 00033 # as well as without $ echo `printf "%05.0f" 33` 00033 

1 Comment

That's because printf takes "0n" as octal. octal 33 = decimal 27. Not hex.
25

to avoid context switching:

a="123" b="00000${a}" c="${b: -5}" 

4 Comments

this! . . . . <3
inverse: while [ "${s:0:1}" = '0' ]; do s=${s:1}; done
Be aware this will cut off numbers which have more than 5 digits. To avoid that, try a="123456"; [[ ${#a} -lt 5 ]] && a="00000${a}" && a="${a: -5}"; echo "$a"
Note: there is no external process invocation ("context switching") in invoking printf. printf is a built-in function in bash, as one can check via man bash.
4
n=`printf '%03d' "2"` 

Note spacing and backticks

Comments

3

As mentioned by noselad, please command substitution, i.e. $(...), is preferable as it supercedes backtics, i.e. `...`.

Much easier to work with when trying to nest several command substitutions instead of escaping, i.e. "backslashing", backtics.

Comments

1

This is in response to an answer given by cC Xx. It will work only until a's value less is than 5 digits.

Consider when a=12345678. It'll truncate the leading digits:

a="12345678" b="00000${a}" c="${b: -5}" echo "$a, $b, $c" 

This gives the following output:

12345678, 0000012345678, 45678 

Putting an if to check value of a is less than 5 digits and then doing it could be solution:

if [[ $a -lt 9999 ]] ; then b="00000${a}" ; c="${b: -5}" ; else c=$a; fi 

1 Comment

Putting an if to check value of a is less than 5 digits and then doing it could be solution.
0

Just typing this here for additional information.

If you know the number of zeroes you need, you can use the string concatenation:

let pad="0" pad+=1 echo $pad # this will print 01 

Comments