Why I can't escape spaces on a bash script?

You are expanding the DESTINATION variable, if you did echo this is what you would get:

echo ${DESTINATION}
/home/hogar/Ubuntu\ One/folder

But mv doesn't understand this:

mv ${FILE} ${DESTINATION}                                                
mv: cannot move '/home/hogar/Documents/files/bdd.encrypted' to '/home/hogar/Ubuntu\\ One/folder': No such file or directory

(for some reason my mv is more verbose)

To prevent this you should use quotes instead:

mv "${FILE}" "${DESTINATION}"

If you don't need expansion (since you are already expanding before) just using "$..." should suffice:

mv "$FILE" "$DESTINATION"

Your step to prepare the variables is "close enough" and will work, but it does show a weakness in understanding (which is why you posted!)

The assignment to DESTINATION needs to be only one of these two:

DESTINATION="/home/hogar/Ubuntu One/folder"

or

DESTINATION=/home/hogar/Ubuntu\ One/folder

The double-quotes turns on quoting (a form which has some magic) and the backslash is capable of quoting a single character following it. Personally I think the form using double-quotes is preferable because visually it's nicer.

By the way, for similar reasons I would do the FILE assignment like:

FILE="${ROOT}bdd.encrypted"

which shows the fairly rare occasion to use ${NAME} instead of simply $NAME - to separate the variable name from any letter following. In fact, if you didn't have a trailing / on the definition of ROOT, I'd be writing

FILE="$ROOT/bdd.encrypted"

which looks even better. It will also give you occasional benefits that I won't go into; let's just say in my experience, trailing slashes tend to be more unwelcome than welcome, and they are definitely not needed. (It does have consequences when it comes to symlinks but that's definitely too much detail on this already large answer).

The crux of your issue is actually taking place at the mv command, which should be written as

mv "$FILE" "$DESTINATION"

because these days, you never know when a variable representing a path will have spaces in it. Once again, note the avoidance of braces for a simple variable expansion.

The reason you got a problem is because of the process the shell uses to construct command lines. If you read the shell manual carefully, it basically says that variables (and a few other things) get expanded THEN it goes looking for spaces. Of course there's some more complexity in the process, but this is the gist of the problem for you.

One further point that's related and well worth knowing about: the distinction between $*, $@, "$*" and "$@". So I'll talk about it!

If you have a shell script that may be called as:

foo -x "attached is the software" "please read the accompanying manual"

then foo will see -x as $1, and the two strings as $2 and $3 (which you should access as "$2" and "$3" for obvious reasons). If, however, you want to pass this entire set of parameters to another script, the following will suffer horrible splitting on all the spaces:

bar $*

and the following (which was the only way in version 0.X of the very original Bourn shell) will cause all the arguments to be passed as a single string (also WRONG)

bar "$*"

so the following syntax was added as a very special magical case:

bar "$@"

which deliberately quotes the individual members of $* as complete quoted strings but keeps them separate. Everyone is a winner now.

It's kinda entertaining to experiment with other effects of $@ when not used as "$@" but you'll quickly find out it's not actually that entertaining... it is merely a special case that solves a major problem.

All the decent modern shells which support arrays also use @ in a special case:

${arr[*]}
"${arr[*]}"
"${arr[@]}"

where the first one will suffer splitting on all spaces, leading to an unpredictable number of separate words, the second will yield all the array members in one string, and the third will very nicely offer each array member as an individual unbroken quoted string.

Enjoy!


Yes you escaped space when you assign the value to $DESTINATION,

But when you use it with mv command, you didn't

mv ${FILE} ${DESTINATION}

Use this instead:

mv "${FILE}" "${DESTINATION}"

Tags:

Shell

Quoting