Search code examples
bashvariablesdouble-quotes

BASH script mv command would not work without double-quoting variables. Why?


I wrote a script today as follows:

echo "Enter a directory path"

read dir

for file in $dir/[!.]*;
    do
        f=`echo $file | sed 's/ /_/g'`
        mv "${file}" "${f}"  
    done

Initially, the mv command was written as:

mv ${file} ${f}

But that line was throwing

usage: mv [-f | -i | -n] [-v] source target
   mv [-f | -i | -n] [-v] source ... directory

I was able to use google to figure out that the variables needed to be wrapped in double quotes, but I still don't understand why doing so resolved the problem?
Thanks!


Solution

  • Quoting, in shell, prevents string-splitting and glob expansion. If you don't double-quote your variables, you have no idea how many arguments each variable may expand into after these parsing steps are run.

    That is:

    mv $foo $bar
    

    ...may turn into...

    mv ./first word second word third word destination-file
    

    if

    foo='./first word second word third word'
    bar='destination-file'
    

    Similarly, consider the case where you have a filename containing a glob expression:

    foo='hello * world'
    

    In that case, your mv command would get a list of all files in the current directory.


    ...or, consider the case when an argument is empty:

    foo='hello world'
    bar=''
    

    In this case, instead of (properly) getting an error that you can't have file with a 0-byte name, you would be trying to rename a file named hello to world: The $bar simply disappears.