For Loops and Space in Names
Cameron Simpson
cs at zip.com.au
Wed Dec 10 23:02:49 UTC 2008
On 10Dec2008 15:05, Robert Wuest <rwuestfc at wuest.org> wrote:
| Spaces have always been one of my pet peeves and I find this discussion
| rather interesting. Spaces don't belong in filenames and they make
| script writing a pain. I'm going to include a script I wrote a long
| time ago to handle the problem of junk characters in music files. Even
| buying music online from Amazon will get you spaces in filenames :(
|
| I remember messing with this little script quite a bit before it worked.
| One lesson I learned writing this was to use lot's of double quotes.
| The script replaces spaces (and other things) in filenames. I just put
| it up here as an example since it's pretty short. I seem to use it a
| lot.
|
| The main for loop is:
|
| for i in *; do
| fixname "$i"
| done
|
| Notice the quotes around "$i". They're important.
[...]
| function fixname()
| {
| newname=`echo $1 | \
Because the $1 is unquoted here you probably don't need the "+" in the
regexps. But you probably should quote $1 because of this:
[/Users/cameron]fleet*> x='t*'
[/Users/cameron]fleet*> echo "$x"
t*
[/Users/cameron]fleet*> echo $x
test.txt them tmp
i.e. if $x is not quoted then glob characters in a filename will get expanded
(supposing you have a name like "t*", and some other files starting with "t").
| sed -r \
| -e "s/[ ]+/_/g" \
| -e "s/[_]+/_/g" \
| -e "s/'//g" \
| -e "s/[+]//g" \
| -e "s/,//g" \
| -e "s/_-_/-/g" \
| -e "s/\&/and/g"`;
| # only do rename if the name is changed
| if [ \"$1\" != \"${newname}\" ]; then
You don't need to backslash the "s in this comparison.
| echo mv \"$1\" \"${newname}\"
This is actually dangerous. By leaving the (expanded) $1 in double
quotes, it is subject to parameter and command substitution in the
shell that runs the commands you generate. For example, supposing I ship
you a file whole name contains:
`rm -rf $HOME`
That _will_ get through your script, and _will_ run the rm command in
the subshell. In both the $1 and $newname parts.
But it gets better. Even though you remove all single quotes form
$newname, and are thus safe to emit:
mv ..... '$newname'
the $1 is still unsafe, and cannot easily be made safe. (Actually,
bash's "printf %q" formatter may do the trick for you, and since you're
already in nonportable GNU sed land, you may as well step right in with
nonportable bash too:-)
Personally, I would change the script mode. Instead of trying to emit
safe shell syntax for piping to "sh", I would instead give it two modes
of operation. Default is to recite commands and a -x option would make
it actually move files around.
Like this:
setx()
{ ( set -x
"$@"
)
}
trace=echo
# handle leading -x option
if [ "x$1" = x-x ]
then
shift
trace=setx
fi
and then down where you emit the mv commands go:
$trace mv "$1" "$newname"
which should be robust against weird names in $1 or $newname.
BTW, have you worried about having mv move a "bad" filename onto an
already existing "good" name? A "mv -i" might avoid a little pain.
| else
| echo "# \"$1\" and \"${newname}\" are the same file"
| fi
| }
|
| if [ "$#" == "0" ]; then
No quotes needed here, and "==" is not a test notation. You want "="
(string comparison) or "-eq" (numeric comparison).
| for i in *; do
| fixname "$i"
| done
| else
| while [ "z$1" != "z" ]; do
| fixname "$1"
| shift
| done
This loop is better written:
for i; do
fixname "$i"
done
otherwise running your script like this:
your-script a b c "" d e f
will only operate on the first 3 names. Besides, the "for i; do" notation
is shorter and clearer (once you know that leaving off the "in" clause
iterates over the command line arguments). And all to frequently you
see this in scripts:
for i in $*; do
which has the usual "spaces in words" trouble we're all working around
here.
Personally, I strive to be robust against weird names in my code, to
avoid having to play rename games like yours. I do have renaming scripts
like your for much the same reason you do, though.
Cheers,
--
Cameron Simpson <cs at zip.com.au> DoD#743
http://www.cskk.ezoshosting.com/cs/
Lady, have you ever seen a cat skeleton in a tree? - Kevin Dunn
More information about the fedora-list
mailing list