Archive for the ‘Bash’ Category

Bash command works, but not when in script!

03/11/2012

As I have a Ubuntu One account (probably everyone has cloud account on some server) I decided to make some backups of data stored there. I’ve tested the following string in my console and everything worked:

tar cf - /home/me/Ubuntu\ One/foo/ | 7z -si ...
tar cf - "/home/me/Ubuntu One/foo/" | 7z -si ... # Alternative solution

Every smart cookie knows that for backups we use cron + scripts. Awesome, so I changed it to following script:

readonly bak_src='/home/me/Ubuntu One/foo/'
tar cf - $bak_src | 7z -si ...

Result?

tar: /home/me/Ubuntu\\: Cannot stat: No such file or directory
tar: One/foo/: Cannot stat: No such file or directory

Ok, that’s simple (space is wrongly handled), let’s do it this way:

# 'Ubuntu\ One' version won't work as the in the final string
# the '\' will be changed to '\\'.
readonly bak_src='/home/me/Ubuntu One/foo/'
tar cf - "$bak_src" | 7z -si ...</pre>

Great, that works. But in fact the string I ended up with was as follows

readonly bak_src='/home/me/Ubuntu\ One/foo/'
readonly cmd="tar cf - ""$bak_src"" | 7z -si ..."
echo $cmd # Returns: tar cf - /home/me/Ubuntu\ One/foo/ ...
$cmd

And … a failure. The old Cannot stat: No such file or directory returns. But why? This doesn’t make any sense; the echoed string is correct (I’ve checked it in the console) but it somehow doesn’t work in a script.

Reason? While the string looks virtually the same, bash doesn’t evaluate the bak_src and treats what is given as two separate command arguments divided by a space. To deal with it, we have to use the eval which forces bash to reevaluate the whole string so that the tokens can be selected correctly.

readonly bak_src='/home/me/Ubuntu\ One/foo/'
readonly cmd="tar cf - ""$bak_src"" | 7z -si ..."
eval $cmd

If you want to read more on this (especially if you didn’t get it from my explanation), read the Waldmann’s guide.

Happy bash hacking!