60

I'm taking a unix/linux class and we have yet to learn variables or functions. We just learned some basic utilities like the flag and pipeline, output and append to file. On the lab assignment he wants us to find the largest files and copy them to a directory.

I can get the 5 largest files but I don't know how to pass them into cp in one command

ls -SF | grep -v / | head -5 | cp ? Directory
Yamiko
  • 5,303
  • 5
  • 30
  • 52
  • 7
    `man xargs` is your friend... – Fredrik Pihl Jul 26 '11 at 16:49
  • See also [How to pass `find` results to `cp` such that file names with spaces work](http://stackoverflow.com/questions/18724826/how-to-pass-find-results-to-cp-such-that-file-names-with-spaces-work). – tripleee Sep 05 '15 at 12:26

4 Answers4

91

It would be:

cp `ls -SF | grep -v / | head -5` Directory

assuming that the pipeline is correct. The backticks substitute in the line the output of the commands inside it.

You can also make your tests:

cp `echo a b c` Directory

will copy all a, b, and c into Directory.

Diego Sevilla
  • 28,636
  • 4
  • 59
  • 87
  • 3
    While this may work, be aware [Why you shouldn't parse the output of ls(1)](https://mywiki.wooledge.org/ParsingLs) – iolsmit Jul 24 '18 at 11:37
  • You're right. It is however difficult to list the files in order by size, and `ls -SF` is easy enough. In fact, this solution is not correct if the files have spaces in them. – Diego Sevilla Jul 25 '18 at 08:20
61

I would do:

cp $(ls -SF | grep -v / | head -5) Directory

xargs would probably be the best answer though.

ls -SF | grep -v / | head -5 | xargs -I{} cp "{}" Directory
gpojd
  • 22,558
  • 8
  • 42
  • 71
9

Use backticks `like this` or the dollar sign $(like this) to perform command substitution. Basically this pastes each line of standard ouput of the backticked command into the surrounding command and runs it. Find out more in the bash manpage under "Command Substitution."

Also, if you want to read one line at a time you can read individual lines out of a pipe stream using "while read" syntax:

ls | while read varname; do echo $varname; done
Rag
  • 6,405
  • 2
  • 31
  • 38
  • That's exactly what I needed to pipe a list of window ids (grepped and cut from the output of `xwininfo`) into the `xdotool` so I could close a bunch of error dialogs that popped up. This syntax works with zsh :) – Desty Feb 10 '16 at 13:14
2

If your cp has a "-t" flag (check the man page), that simplifies matters a bit:

ls -SF | grep -v / | head -5 | xargs cp -t DIRECTORY

The find command gives you more fine-grained ability to get what you want, instead of ls | grep that you have. I'd code your question like this:

find . -maxdepth 1 -type f -printf "%p\t%s\n" | 
sort -t $'\t' -k2 -nr | 
head -n 5 | 
cut -f 1 | 
xargs echo cp -t DIRECTORY
glenn jackman
  • 238,783
  • 38
  • 220
  • 352