If you don't quote the file name, the shell has no way of knowing that foo bar.txt
is one parameter and not two (foo
and bar.txt
). You therefore need to call your script like this:
./chExt.sh txt ocelot.cpp ../otherFolder/file.H cat.dog.TXT "king cobra.dat"
The next problem is that when variables are expanded, the resulting value is split on whitespace (or whatever the $IFS
variable is set to). So, when you write for i in $*
, the $*
is expanded and split on whitespace. Therefore, $i
becomes king
for one iteration and cobra.txt
for the next. The way around that is to quote the variable you want to expand so that it is not split.
Which brings us to the next issue which is the difference between $*
and $@
. If you use "$*"
, the parameters will all be treated as one long string:
$ cat foo.sh
#!/bin/sh
for i in "$*"; do
echo "$i"
done
$ foo.sh foo "bar baz"
foo bar baz
Compare the above to:
#!/bin/sh
for i in "$@"; do
echo "$i"
done
$ foo.sh foo "bar baz"
foo
bar baz
As you can see, using "$@"
has the desired effect, each input parameter is treated separately, including the one with spaces.
As a final note, your script will also choke on file names starting with -
and a letter corresponding to an option for echo
(try with a file called -new
, for example). A better way to strip the extension is to use the shell's native string manipulation features. ${var%.*}
removes the shortest string matching a .
and 0 or more characters from the end of the variable. In other words, the extension. Then, you also need to add --
to mv
to indicate the end of option and the start of parameters so that it too can deal with file names starting with -
(see Guideline 10 here).
So, an improved and working version of your script would be:
#!/bin/sh
newExt="$1"
shift
for fileName in "$@"
do
if test -f "$fileName";
then
# name=$(echo "$fileName" | rev | cut -f 2- -d '.' | rev)
name=${fileName%.*}
newName="$name.$newExt"
if test "$newName" != "$fileName";
then
mv -- "$fileName" "$newName"
fi
else
printf '%s: No such file\n' " $fileName"
fi
done
Further reading:
king\ cobra.dat
or"king cobra.dat"
$()
is kind of a Bashism ... at least not supported in pure POSIX shells. Why don't you make use of string substitution to cut off the extension (${i%.*}
) and of"$@"
in thefor
loop? After all you seem to have some shell available which allows this.sh
on any given system. AFAIK a lot of features were pioneered and spread by particular shells and later standardized in SUS.