Bash format variable for command

From my bash shell, I would like to call the program n times with another numbered parameter, which should be in a fixed format, for example "% 02i"

One of the methods:

for ((i=23; i<42;i++)); do sh ../myprogram `printf "%02i\n" $i` done 

Is there a way to improve the printf.. part? I believe that this can be a performance bottleneck with a large number of files and makes the line less readable than the built-in function (especially when it is compressed to a single line).

+6
bash shell
source share
5 answers

In Bash, printf provided by the shell (see bash (1) man page , find "printf"), so you don’t even have the (minimum) fork() and exec() overheads to execute a separate command - if you didn't run it from reverse cycles. Bash's built-in printf allows you to assign the output of this variable to the -v argument; your script fragment can be rewritten as:

 for ((i=23; i<42;i++)); do printf -v ii "%02i\n" $i sh ../myprogram $ii done 

I'm not sure I think it is more readable than the original.

The most resource-intensive part of your script fragment calls your other shell script; I would not worry about the overhead of calling printf, unless other data indicates otherwise.

edited to add the difference between callbacks and direct execution

+20
source share

Your number already has 2 decimal places. Why do you need to use printf? If I remember correctly (I don’t have a shell for testing here), it simply fills up to 2 decimal places when used with these flags. Personally, I like xargs:

 seq 23 42 | xargs -n1 sh ../myprogram 

You can use the -w argument to seq , which fills the numbers with zeros if necessary, so they have the same width.

It turns out seq is specific to Linux. Thanks to Dave for comments for his clarification (his answer ). Use printf directly, without a loop:

 printf '%02i\n' {23..42} | xargs -n1 sh ../myprogram 

I like to use xargs , because it allows you to easily run your commands in parallel to a certain limit, can transfer more than one number at a time, and allows you to use other flexible options. Like Dave, I recommend that you give up sh and put it in your shell script instead of the first line:

 #!/bin/sh ..... 

Then just do your things like

 printf '%02i\n' {23..42} | xargs -n1 ../myprogram 

This is more general and allows your script to also be called when the exec C library is called (at least on Linux, in this case).

+6
source share

FYI: a completely different solution:

 jot -w "%02i" - 23 42 | xargs -n 1 ../myprogram 

This has a performance flaw when calling jot (the standard with 4.2BSD therefore all BSD derivatives have this, but a quick glance shows that this main great tool seems to be missing from the Linux distributions I was looking at). Edit : Linux (at least Red Hat) seems to have a subset of the jot functions in the seq command (thanks litb answer for this info).

It is also useful for working with non-bash shells (as opposed to the fact that, according to some people, more than one shell is actively used, and shell-agnostic solutions are a good idea).

+2
source share

What about

 for i in {23..42} ; do sh ../myprogram $i done 

Numbers between 23 and 42 will always be in the format% 02i.

If you absolutely must format, then

 for i in {23..42} ; do printf "%02i\n" | xargs -n1 sh ../myprogram $i done 

Replaces overhead with irregular xargs for overhead for spawning subshells for reverse cycles. I have no idea which is more efficient.

+1
source share

to try:

 seq -w 23 41 

This fills with the upper number 0 automatically to the required size

or

 seq -f "%02g" 1 29 

This will format up to two digits.

Thus, the complete command:

 for i in `seq -f "%02g" 23 41`; do sh ../myprogram $i done 
-one
source share

All Articles