Bash can seem pretty random and weird at times, but most of what people see as quirks have very logical (if not very good) explanations behind them. This series of posts looks at some of them.
# Why can't you use variables in {}? for i in {0..$n}; do ..
Short answer: {..} is expanded before $n
Shell execution is based on successive expansions. {..} is evaluated early, before variable expansion, and thus you can’t use variables in them.
This also implies that you can use {..} in variable names, like a1=foo; a2=bar; echo $a{1,2}
.
Instead, use for ((i=0; i<n; i++)); do ...
.
# Why aren't any of the Linux rename tools like Windows 'ren'? touch foo0001.jpg foo0002.jpg ren foo*.jpg bar*.jpg # Windows rename foo bar foo*.jpg # Coreutils rename rename 's/foo/bar/' foo*.jpg # Perl (debian) rename
Short answer: globs are expanded before the command sees them
Bash expands globs before running the command. This means that running rename foo*.jpg bar*.jpg
is exactly the same as running rename foo0000.jpg foo0001.jpg ...
. Since rename can’t know what pattern was originally used, it has to use an alternative syntax.
Of course, you could write a rename where you quote the globs, like rename "foo*.jpg" "bar*.jpg"
, but that’s not simpler than the coreutils version. It just adds complexity, edge cases and general confusion.
There have been proposals for environment variables to set so that commands can see the shell arguments with globs intact, but that has its own problems so they weren’t widely used.