I have a list of files separated by spaces in a file list.txt. I'd like to copy them to a new folder.

I tried to do:

cp `cat list.txt` new_folder

but it did not work.

How would you do this ?


Thank you for all your very interesting answers. I did not ask for that much :)

After having tried the solution above a second time, it seems that cp printed the usage help because the folder new_folderdid not exist yet! Sorry, it seems to be a stupid mistake... When I create the folder before, it works.

However, I have learnt much from all your answers and solutions, thank you for the time you take to write them.

  • Let me get one thing clear: the list has all the file names on one line, separated only by a space? Or are the names each on a separate line?
    – Telemachus
    Aug 24, 2010 at 21:19
  • All in one lime, separated by a space. Doug's solution worked :) Thank you for the answer.
    – Klaus
    Aug 24, 2010 at 21:22
  • That's funny... I tested my solution with a line in which each name was on a separate line. Aug 24, 2010 at 21:59
  • "it did not work" isn't very meaningful. Exactly how did it not work. It works fine for me. Aug 25, 2010 at 1:45
  • Sorry: it showed cp usage help. See my update above.
    – Klaus
    Aug 25, 2010 at 22:10

4 Answers 4


Try using xargs:

cat list.txt | xargs -J % cp % new_folder


I did this on OS X which has an different version than GNU/Linux versions. The xargs which comes from GNU findutils doesn't have -J but it has -I which is similar (as Dennis Williamson pointed out in a comment). The OS X version of xargs has both -I and -J which have slightly different behaviors -- either will work for this original question.

$ cat list.txt

$ cat list.txt | xargs -J % echo cp % new_folder
cp one two.txt three.rtf new_folder

$ cat list.txt | xargs -I % echo cp % new_folder
cp one new_folder
cp two.txt new_folder
cp three.rtf new_folder
  • 4
    My xargs doesn't have -J it has -I which seems to do the same thing. What version of xargs and what OS/distribution do you have? Aug 25, 2010 at 14:19
  • I tested this on Mac OS X 10.6 (aka snow leopard), so it's whatever version of xargs ships with the OS. Running xargs --version returns a usage error message. It's likely a BSD version of xargs. The use of -I and -J are subtly different. I'll update my answer with nicely formatted examples. Aug 25, 2010 at 15:59
  • Yep, I'm working with Mac OSX 10.6. Thank you for the precisions about -J and -I :)
    – Klaus
    Aug 25, 2010 at 21:50
  • That's a good tip to use echo to check your commands before you run them.
    – Liam
    Oct 9, 2014 at 13:14
  • 1
    Using same above command with necessary changes only, how do I copy the files along with creating their directories and subdirs they are in, separated by slash ?
    – Vicky Dev
    May 21, 2016 at 7:57

No need for cat at all:

xargs -a list.txt cp -t new_folder

Or using long options:

xargs --arg-file=list.txt cp --target-directory=new_folder

Here are some shell versions. Note that some variables are unquoted or for loops are used specifically because the OP specified that the filenames are space delimited. Some of these techniques won't work for filename-per-line input in which filenames contain white space.


for file in $(<list.txt); do cp "$file" new_folder; done


cp $(<list.txt) new_folder

sh (or Bash):

# still no cat!
while read -r line; do for file in $line; do cp "$file" new_folder; done; done < list.txt


# none here either
while read -r line; do cp $line new_folder; done < list.txt


# meow
for file in $(cat list.txt); do cp "$file" new_folder; done


# meow
cp $(cat list.txt) new_folder
  • noob question: why is -t needed in xargs -a list.txt cp -t new_folder?
    – Yibo Yang
    Jun 29, 2017 at 22:41
  • 1
    @YiboYang: The -t is an option of cp. It copies all source arguments into the specified target directory. Here, it allows the target to be specified before the source which is added by the xargs command. Jun 30, 2017 at 20:29
  • This is useful but what if list.txt contains mixed files and folders path ? In that case the command doesn't works properly. It reports "omitting directory ..." and if -R is specified to the cp command then the "is not a directory" error is reported as soon as the first file in the list is encountered.
    – Bemipefe
    Feb 21, 2018 at 16:36
  • There is no -a option on MacOS.
    – tasty
    Sep 26 at 10:20

I had an embarrassingly round-about answer here earlier, but Denis's answer reminded me that I missed the most basic thing. So, I deleted my original answer. But since nobody has said this very basic thing, I think it's worth putting it here.

The original question is "I have a text file with a list of space-separated names of files. How can I copy those to one target directory." At first this might seem tricky or complicated, because you think you have to somehow extract the items from the file in a specific way. However, when the shell processes a command line, the first thing it does is separate the argument list into tokens and (here's the bit nobody has said outright) spaces separate tokens. (Newlines also separate tokens which is why Doug Harris's test with a newline separated list had the same result.) That is, the shell expects and can already handle a space-separated list.

So all you need to do here is put the space-separated list (that you already have) into the right place in your command. Your command is some variation on this:

cp file1 file2 file3...file# target

The only wrinkle is that you want to get the list of files 1 through # from your text file.

As Dennis points out in his comment, your original attempt (cpcat list.txtnew_folder) should have worked already. Why? Because the internal command cat list.txt is processed first by the shell and expands into file1 file2 file3...file#, which is exactly what the shell expects and wants at that part of the command. If it didn't work then either (1) you had a typo or (2) your filenames were somehow strange (they had spaces or other unusual characters).

The reason that all Dennis's answers work is simply that they provide the necessary list of files for cp to work on, placing that list where it belongs in the entire command. Again, the command itself is this in structure:

cp list-of-files target_directory

It's easy to see how this all comes together in this version:

cp $(<list.txt) new_folder

$() causes the shell to run the command inside the parentheses and then substitute its output at that point in the larger line. Then the shell runs the line as a whole. By the way, $() is a more modern version of what you were already doing with backticks (`). Next: < is a file redirection operator. It tells the shell to dump the contents of list.txt to standard input. Since the $() bit gets processed first, here's what happens in stages:

  1. cp $(<list.txt) new_folder # split line into three tokens: cp, $(<list.txt), new_folder
  2. cp file1 file2 file3...file# new_folder # substitute result of $(<list.txt) into the larger command

Obviously step 2 is simply the normal cp command you wanted.

I realize that I'm beating this (perhaps very dead) horse a lot, but I think it's worth doing. Understanding exactly how the shell processes a command can help you to write it better and simplify a lot. It will also show you where problems are likely to be hiding. In this case, for example, my first question to you should have been about funny filenames or a possible typo. No acrobatics were necessary.

  • @Klaus You're very welcome. To be frank, I was mostly annoyed at myself after reading Dennis's answer and realizing that I missed the key part of the problem entirely. The solution you like is from there as well.
    – Telemachus
    Aug 25, 2010 at 23:09
  • 2
    This is a super old answer, but if you need to re-create the folder structure, you need the --parents flag. You can make it verbose with -v for a record of what was copied. If you want to keep permissions, you need the -a or -p flag. Ie, cp --parents -av $(<list.txt) new_folder. This is all assuming your list of files are really all files, else you may also need the -r flag to recurse as well.
    – dhaupin
    May 24, 2017 at 20:11
  • @dhaupin Actually, the OP states that he was on macOS. So for what it's worth, the --parents flag doesn't exist there. Their (BSD-derived) version of cp only provides short options, not GNU-style long options. For a BSD-style cp, the flag for recursive copy is uppercase -R, not lowercase.
    – Telemachus
    May 31, 2017 at 13:27

In addition to the answer from @dennis-williamson:

If you have a file with comments and want to use xargs, exclude with lines beginning with # using grep:

grep -e '^[^#]' filelist.txt | xargs \
    cp --parents \
    --target-directory "$TARGET_PATH"

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.