Friday, February 05, 2010

Bash! You are killing me! How to escape spaces in filenames being passed to tar


Bash can be really frustrating!

I'm trying to take all the files that match a pattern and put them in a tar.gz file. Sounds simple?
aj@aj-laptop:/home/aj$ find . -name "*tips*"
./data/DRAFT/tips and tricks.doc
./data/DRAFT/tips new.doc

Looks okay till here. But -

aj@aj-laptop:/home/aj$ find . -name "*tips*" | xargs tar czvvf tips.tar.gz
tar: ./data/DRAFT/tips: Cannot stat: No such file or directory
tar: and: Cannot stat: No such file or directory
tar: tricks.doc: Cannot stat: No such file or directory
tar: ./data/DRAFT/tips: Cannot stat: No such file or directory
tar: new.doc: Cannot stat: No such file or directory
tar: Error exit delayed from previous errors
aj@aj-laptop:/home/aj$
Apparently it would not work fine when your filenames have spaces in them because then it would tokenise them with spaces and hence break up the file names.

So I search around on the web and find a bunch of things to try on a stackoverflow thread.

And here's the solution that worked -
aj@aj-laptop:/home/aj$ find . -name "*tips*" -print0 | xargs -0 tar czvvf tips.tar.gz
-rwx------ aj/aj 31232 2010-01-12 19:23 ./data/DRAFT/tips and tricks.doc
-rwx------ aj/aj 30208 2008-10-08 16:57 ./data/DRAFT/tips new.doc
aj@aj-laptop:/home/aj$
Basically adding -print0 to the find command makes it separate strings by NULLs (\0s) which can never be a part of the filenames and can never cause problems.Note that you also need to tell xargs to separate strings by NULLs by passing the -0 flag.

But now since I couldn't find any such flags for other standard linux commands like grep, this solution is only useful when I need to pass the output from find straight into tar. For example I cannot do find . -name "*tips*" -print0 | grep 'tricks' | xargs -0 tar czvvf tips_and_tricks.tar.gz !

Sad! But I am done for the day with this problem. Please let me know in the comments if there is a general solution to this.

3 comments:

Jon Watte said...

I found this when looking for something totally different, but I can help you.
The problem is that you're using xargs. Tar is made to read a list of files from stdin.
Simply pass "-T -" as an argument, avoid the overhead of xargs, and you're good to go!

PSPMAN90 said...

LOL! Nice pic!!! You dont mind if I borrow it :p

PSPMAN90 said...
This comment has been removed by the author.