3

Im looking to copy the first 'n' files from one directory to another directory preferably with only cli tools (no scripts).

I've tried the following:

  • find . -maxdepth 1 -type f | head -5 | xargs cp -t /target/directory

    This looked promising, but failed because osx cp command doesn't appear to have the
    -t switch

  • exec in a few different configurations

    This probably failed for syntax problems on my end : /
    I couldn't seem to get a head type selection working

Any help or suggestions would be appreciated.

Thanks in advance!

0

2 Answers 2

4

You need the -J option with xargs.

find . -maxdepth 1 -type f | head -n5 | xargs -J X cp X /target/directory

The J option places all the filenames into the placeholder X, which can be any character(s) and cp accepts multiple files to a target directory. It can be visualized as-

cp file1 file2 file3 file4 file5 DESTINATION

EDIT:

To handle filenames with spaces, we have tr translate the newline character to the null character after each filename and then have xargs handle the null bit as a separator for the filenames.

 find . -maxdepth 1 -type f | head -n5 | tr '\n' '\0' | xargs -0 -J X cp -- X /target/directory
9
  • Excellent solution, just what I was after! Could you explain the 'n' in head -n5? At any rate, big thanks, and thanks @user3439894 for your input as well!
    – visyoual
    Sep 13, 2018 at 17:21
  • @visyoual - From the manual: ` head [-n count | -c bytes] [file ...]`
    – fd0
    Sep 13, 2018 at 17:30
  • Ok. In my search for other solutions prior to posting this questions, several had the head command with -5 and not -n5. Wasn't sure if that was acceptable shorthand, or syntax error. I guess i'm still not sure.
    – visyoual
    Sep 13, 2018 at 17:33
  • As you mentioned to me in a comment to my answer, your solution does not handle filenames with spaces, it there a way to achieve it modifying your command slightly? Sep 13, 2018 at 17:37
  • 1
    @visyoual - depends on the version of head that you are using, With GNU head -n5 would mean the first five lines and -5 would mean all but the last five lines. With BSD head both are the same.
    – fd0
    Sep 13, 2018 at 17:45
1

I found a different solution without xargs or -exec but I think fd0's answer is a better way to go:

while IFS= read -r f; do cp "$f" "/target/directory/"; done < <(find . -maxdepth 1 -type f | head -n5)
3
  • 2
    I'll suggest the you set IFS to nothing-IFS= to handle any leading or trailing spaces in a filename and use process substitution instead of command substitution and a here string. Your solution will definitely be slower but it will handle filenames with spaces in them. My solution will not in its current form.
    – fd0
    Sep 13, 2018 at 16:38
  • @fd0, Good suggestion. I know with IFS= it would be IFS=; while read ... but not sure how to swap out the command substitution and here string for process substitution instead, without doing some research. Would not mind you showing me or even editing my answer, thanks. Sep 13, 2018 at 16:57
  • Thanks @fd0, I missed the extra < in ... done < <( ... in my testing. :) Sep 13, 2018 at 17:06

You must log in to answer this question.

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