Reputation: 22370
From my bash shell I would like to call a program n times with a different numbered parameter, which has to be in a fixed format like "%02i"
One way would be:
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 this might be a performance bottleneck with more files and makes the line less readable than a built-in function (especially when condensed to a one-liner).
Upvotes: 5
Views: 27912
Reputation: 1
try:
seq -w 23 41
This will fillup with leading 0 automatically to needed size
or:
seq -f "%02g" 1 29
This will format to exact 2 digits.
So complete command would be:
for i in `seq -f "%02g" 23 41`; do
sh ../myprogram $i
done
Upvotes: -1
Reputation: 33370
In Bash, printf
is provided by the shell (see the bash(1) manpage, search for "printf"), so you don't even have the (minimal) overhead of fork()
and exec()
to execute a separate command -- unless you run it from within backticks. Bash's built-in printf lets you assign the output to a given variable with the -v
argument; your script fragment could 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'd consider that more readable than the original.
The most resource-intensive part of your script fragment is calling your other shell script; I wouldn't worry about the overhead of calling printf unless further evidence indicates otherwise.
edited to add the difference between backticks and direct execution
Upvotes: 20
Reputation: 506905
Your number already has 2 decimal places. Why do you need to use printf then? If i remember correctly (haven't got a shell for testing here), it just pads the number up to 2 decimals when used with those flags. Personally, i like xargs:
seq 23 42 | xargs -n1 sh ../myprogram
You can use the -w
argument for seq
, which pads the numbers with zeros if necessary, so they have all the same width.
It turns out seq
is linux specific. Thanks for Dave in the comments for figuring it out (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 easily running your commands in parallel up to some limit, can pass more than one number at once and allows other flexible options. Like Dave, i recommend you to drop the sh
from it, and place it into your shell script, as first line instead:
#!/bin/sh
.....
Then just execute your stuff as
printf '%02i\n' {23..42} | xargs -n1 ../myprogram
This is more generic, and allows your script also to be called by the exec
C library calls (at least in Linux, that's the case).
Upvotes: 5
Reputation: 7878
FYI: A completely different solution:
jot -w "%02i" - 23 42 | xargs -n 1 ../myprogram
This has the performance downside of calling jot (standard since 4.2BSD so all the BSD derivatives have it, but a quick look shows that this basic wonderful tool appears to be lacking from the Linux distributions I looked at). Edit: Linux (at least Red Hat) appears to have a subset of jot's features in a command called seq (thanks to litb's answer for this info).
This has the benefit of working in non-bash shells as well (unlike what some people think, there is more than one shell in active use and shell-agnostic solutions are generally a good idea).
Upvotes: 1
Reputation: 182792
How about
for i in {23..42} ; do
sh ../myprogram $i
done
Numbers between 23 and 42 are always going to be in %02i format.
If you absolutely must format, then
for i in {23..42} ; do
printf "%02i\n" | xargs -n1 sh ../myprogram $i
done
Substitutes the overhead of spawning xargs for the overhead of spawning the subshell for the backticks. I have no idea which is more efficient.
Upvotes: 0