Differences between revisions 3 and 7 (spanning 4 versions)
Revision 3 as of 2008-03-10 10:52:49
Size: 2625
Editor: 134
Comment: seq might be considered bad style
Revision 7 as of 2008-05-15 18:20:16
Size: 3521
Editor: GreyCat
Comment: awk solution too! And clean up the transition from theory to porn.
Deletions are marked like this. Additions are marked like this.
Line 2: Line 2:
Line 7: Line 6:
Line 9: Line 7:
    # Bash
Line 14: Line 13:
Line 15: Line 15:
Line 23: Line 22:
Line 24: Line 24:
Line 26: Line 25:
    for ((i=1; i<=10; i++))     # Bash 2 for-loop syntax     # Bash
for ((i=1; i<=10; i++))
Line 31: Line 31:
Line 32: Line 33:
{{{
   # Bash 3
   printf "%03d\n" {1..300}
}}}
Line 33: Line 38:
If you don't know in advance what the starting and ending values are:
Line 34: Line 40:
   printf "%03d\n" {1..300} # Bash 3 brace expansion    # Bash 3
   # START and END are variables containing integers
   eval printf '"%03d\n"' {$START..$END}
Line 36: Line 44:
The KornShell and KornShell93 have the {{{typeset}}} command to specify the number of leading zeros:
Line 38: Line 45:
The `eval` is needed here because you cannot have variables in a brace expansion -- only constants. The extra quotes are required by the `eval` so that our `\n` isn't changed to an `n`. Given how messy that `eval` solution is, please give serious thought to using the `for` loop instead.

The KornShell has the {{{typeset}}} command to specify the number of leading zeros:
Line 39: Line 49:
    # Korn
Line 43: Line 54:
Line 44: Line 56:
Line 48: Line 59:
Line 49: Line 61:
Line 53: Line 64:
Line 54: Line 66:
Line 56: Line 67:
   # POSIX
Line 58: Line 70:
Line 62: Line 75:
Finally, the following example works with any BourneShell derived shell to zero-pad each line to three bytes:
Finally, the following example works with any BourneShell derived shell (which also has `expr` and `sed`) to zero-pad each line to three bytes:
Line 65: Line 77:
   # Bourne
Line 73: Line 86:
Line 75: Line 89:
Now, since the number one reason this question is asked is for downloading images in bulk, you can use the {{{printf}}} command with {{{xargs(1)}}} and {{{wget(1)}}} to fetch files: But if you're going to rely on an external Unix command, you might as well just do the whole thing in `awk` in the first place:
{{{
   # Bourne
   # COUNT variable contains an integer
   awk "BEGIN {for (i=1;i<$COUNT;i++) {printf(\"%03d\n\",i)} }"
}}}
Line 77: Line 96:
Now, since the number one reason this question is asked is for downloading images in bulk, you can use the examples above with {{{xargs(1)}}} and {{{wget(1)}}} to fetch files:
Line 78: Line 98:
   printf "%03d\n" {$START..$END} | xargs -i% wget $LOCATION/%    almost any example above | xargs -i% wget $LOCATION/%
Line 80: Line 100:
Or, in a slightly more general case:
Line 82: Line 101:
The `xargs -i%` will read a line of input at a time, and replace the `%` at the end of the command with the input.

Or, a simpler example using a `for` loop:
Line 83: Line 105:
   # Bash

Anchor(faq18)

How can I use numbers with leading zeros in a loop, e.g. 01, 02?

As always, there are different ways to solve the problem, each with its own advantages and disadvantages.

If there are not many numbers, BraceExpansion can be used:

    # Bash
    for i in 0{1,2,3,4,5,6,7,8,9} 10
    do
        echo $i
    done

Output:

   00
   01
   02
   03
   [...]

This gets tedious for large sequences, but there are other ways, too. If you have the printf command (which is a Bash builtin, and is also POSIX standard), it can be used to format a number:

    # Bash
    for ((i=1; i<=10; i++))
    do
        printf "%02d " "$i"
    done

In Bash 3, you can use ranges inside brace expansion. Also, since printf will implicitly loop if given more arguments than format specifiers, you can simplify this enormously:

   # Bash 3
   printf "%03d\n" {1..300}

If you don't know in advance what the starting and ending values are:

   # Bash 3
   # START and END are variables containing integers
   eval printf '"%03d\n"' {$START..$END}

The eval is needed here because you cannot have variables in a brace expansion -- only constants. The extra quotes are required by the eval so that our \n isn't changed to an n. Given how messy that eval solution is, please give serious thought to using the for loop instead.

The KornShell has the typeset command to specify the number of leading zeros:

    # Korn
    $ typeset -Z3 i=4
    $ echo $i
    004

If the command seq(1) is available (it's part of GNU sh-utils/coreutils), you can use it as follows:

    seq -w 1 10

or, for arbitrary numbers of leading zeros (here: 3):

    seq -f "%03g" 1 10

Combining printf with seq(1), you can do things like this:

   # POSIX
   printf "%03d\n" $(seq 300)

(That may be helpful if your version of seq(1) lacks printf-style format specifiers. Since it's a nonstandard external tool, it's good to keep your options open.)

Be warned however that seq might be considered bad style, it's even mentioned in ["Don't Ever Do These"].

Finally, the following example works with any BourneShell derived shell (which also has expr and sed) to zero-pad each line to three bytes:

   # Bourne
   i=0
   while test $i -le 10
   do
       echo "00$i"
       i=`expr $i + 1`
   done |
       sed 's/.*\(...\)$/\1/g'

In this example, the number of '.' inside the parentheses in the sed command determines how many total bytes from the echo command (at the end of each line) will be kept and printed.

But if you're going to rely on an external Unix command, you might as well just do the whole thing in awk in the first place:

   # Bourne
   # COUNT variable contains an integer
   awk "BEGIN {for (i=1;i<$COUNT;i++) {printf(\"%03d\n\",i)} }"

Now, since the number one reason this question is asked is for downloading images in bulk, you can use the examples above with xargs(1) and wget(1) to fetch files:

   almost any example above | xargs -i% wget $LOCATION/%

The xargs -i% will read a line of input at a time, and replace the % at the end of the command with the input.

Or, a simpler example using a for loop:

   # Bash
   for i in {1..100}; do
      wget "$prefix$(printf %03d $i).jpg"
      # other commands
   done

BashFAQ/018 (last edited 2019-08-21 16:24:29 by GreyCat)