2

I was attempting to copy files listed in a text file into a directory such as:

cat files.txt | xargs  -I{} cp "{}" ~/Desktop/temp

However I noticed that some files would not copy over. The files that wouldn't copy over had double spaces in the name such as "My   Document.pdf".

I did a little testing and simply piping an echo removes all the spaces except for one. For example:

echo "Hello         World" | xargs echo

simply returns

Hello World

Is there a way when piping to tell it to preserve existing whitespaces in the content?

3
  • What is creating this 'files.txt'? If it is coming from find, then you really should be using the -print0 combined with --null.
    – Zoredache
    Jul 2, 2014 at 0:35
  • In any case take a long read of the docs related to the -d, and --null options. linux.die.net/man/1/xargs
    – Zoredache
    Jul 2, 2014 at 0:37
  • No its not coming from find. I was using cat as example. I have a perl script that will show the paths of files coming from a OS X Smart Folder.
    – Scott Walter
    Jul 2, 2014 at 15:20

3 Answers 3

1

xargs does an unfortunate amount of parsing on its input, and depending on what characters occur in filenames (spaces, quotes/apostrophes, backslashes, tabs, etc) it can mangle them in a number of ways. The best way to handle filenames is as a null-delimited list and using xargs -0 (which turns off all of the parsing). If the file list were generated from find, this would easy (just use -print0). Since you're dealing with output from a perl script, I see two options: modify the perl script to output nulls instead of linefeeds, or if you can't do that convert them in the pipeline with tr:

cat files.txt | tr "\n" "\0" | xargs -0 -I{} cp "{}" ~/Desktop/temp
1
  • Simplier than my sed approach. Thanks for the tip! Jul 3, 2014 at 12:43
1

I found a solution in which I needed to replace a space with a backslash and a space on OS X. Here is what I came up with:

echo "Hello        World" | sed 's/ /\\ /g' | xargs echo

With this all the spaces are retained.

0

You can use a while loop:

while IFS= read -r _file
do
    cp "$_file" ~/Desktop/temp
done < "files.txt"

IFS is set to null causes no splitting is performed, and -r tell bash escapes backslash character.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .