I want to run certain actions on a group of lexicographically named files (01-09 before 10). I have to use a rather old version of FreeBSD (7.3), so I can't use yummies like echo {01..30}
or seq -w 1 30
.
The only working solution I found is printf "%02d " {1..30}
. However, I can't figure out why can't I use $1
and $2
instead of 1
and 30
. When I run my script (bash ~/myscript.sh 1 30
) printf says {1..30}: invalid number
AFAIK, variables in bash are typeless, so how can't printf accept an integer argument as an integer?
Bash supports C-style for loops:
The syntax you attempted doesn't work because brace expansion happens before parameter expansion, so when the shell tries to expand
{$1..$2}
, it's still literally{$1..$2}
, not{1..30}
.The answer given by @Kent works because
eval
goes back to the beginning of the parsing process. I tend to suggest avoiding making habitual use of it, aseval
can introduce hard-to-recognize bugs -- if your command were whitelisted to be run bysudo
and$1
were, say,'$(rm -rf /; echo 1)'
, the C-style-for-loop example would safely fail, and the eval example... not so much.Granted, 95% of the scripts you write may not be accessible to folks executing privilege escalation attacks, but the remaining 5% can really ruin one's day; following good practices 100% of the time avoids being in sloppy habits.
Thus, if one really wants to pass a range of numbers to a single command, the safe thing is to collect them in an array:
I guess you are looking for this trick:
Ok, I finally got it!
I initially wanted to use the cycle iterator as a "day" in file names, but now I see that in my exact case it's easier to iterate through normal numbers (1,2,3 etc.) and process them into lexicographical ones inside the loop. While using
jot
, remember that$1
is the numbers amount, and the$2
is the starting point.