63

Possible Duplicate:
How to move 100 files from a folder containing thousands?

Is it possible to copy only the first 1000 files from a directory to another?

Thanks in advance

chchrist
  • 733
  • 1
    What do you mean by "first"? Did you look at this related question ? – Mat Jan 16 '12 at 12:14
  • If a folder has 50000 files copy only the first 1000. I'll look at the question thnx. – chchrist Jan 16 '12 at 12:24
  • 1
    What to you mean by "first"? Alphabetical? By time changed/accessed? Any set of 1000? – Mat Jan 16 '12 at 12:25
  • Any without criteria – chchrist Jan 16 '12 at 12:31
  • 1
    Sounds like you are trying to copy files using batches. – Russell Jan 16 '12 at 12:50
  • Yes that's what I am trying to do. – chchrist Jan 16 '12 at 12:52
  • 1
    Since I can't answer: this solution seems like the cleanest of them all: cp \ls | head -500` ./subfolder1/. You might want to be in the directory to copy from such thatls` can work properly. Also, it assumes none of the filenames contain space, tab, newline, star, open square bracket, question mark characters or start with - or . and assuming subfolder1 itself does not show up in that list (credits to https://unix.stackexchange.com/questions/105040/how-to-move-the-first-x-files). – Marcel Braasch May 31 '20 at 08:59

3 Answers3

91

The following copies the first 1000 files found in the current directory to $destdir. Though the actual files depend on the output returned by find.

$ find . -maxdepth 1 -type f |head -1000|xargs cp -t "$destdir"

You'll need the GNU implementation of cp for -t, a GNU-compatible find for -maxdepth. Also note that it assumes that file paths don't contain blanks, newline, quotes or backslashes (or invalid characters or are longer than 255 bytes with some xargs implementations).

EDIT: To handle file names with spaces, newlines, quotes etc, you may want to use null-terminated lines (assuming a version of head that has the -z option):

find . -maxdepth 1 -type f -print0 | head -z -n 1000 | xargs -0 -r -- cp -t "$destdir" --
terdon
  • 242,166
  • @chchrist, Mark this as answer. – shgnInc May 04 '14 at 06:09
  • 2
    doesn't work to me if paths has spaces in it – miguelfg Jan 20 '16 at 16:39
  • @onur I couldn't find any version of head that has a '-z' option. Otherwise thanks for the improvement Then the above edit doesn't work as intended(ie. there's no 1000 files limit anymore, it's all files), if head isn't treating lines as null terminated! head -z exists for me on Fedora 25: $ rpm -qf /usr/bin/head result coreutils-8.25-17.fc25.x86_64 package. Also see this answer where I used head -z. I'm curious, what distribution did you check for head -z availability? Thanks. –  Sep 09 '18 at 04:30
  • There is a workaround for those not having head -z see: https://unix.stackexchange.com/a/467073/306023 So the above becomes then: find . -maxdepth 1 -type f -print0 | tr '\0\n' '\n\0' | head -n 1000 | tr '\0\n' '\n\0' | xargs -0 -r -- echo -t "$destdir" -- ie. replace head -z -n 1000 with tr '\0\n' '\n\0' | head -n 1000 | tr '\0\n' '\n\0' –  Sep 09 '18 at 06:14
  • head -z gives invalid option error in Debian jessie/sid version. – onur güngör Sep 10 '18 at 07:21
  • 2
    @onurgüngör Marcus is right though, if you've got find printing everything on one line with -print0, head isn't going to work, so I don't think your last example is right. Want to incorporate the workaround posted in that comment instead? – Michael Mrozek Sep 11 '18 at 14:30
  • 2
    @onurgüngör I think you need to update your version. The man page listed for sid does include the -z. – terdon Sep 12 '18 at 11:46
4

A pure shell solution (which calls cp several times).

N=1000;
for i in "${srcdir}"/*; do
  [ "$((N--))" = 0 ] && break
  cp -t "${dstdir}" -- "$i"
done

This copies a maximum number of $N files from $srcdir to $dstdir. Files starting with a dot are omitted. (And as far as I know there's no guaranty that the set of chosen files would even be deterministic.)

0

The following scary 1-liner:

perl -MFile::Copy -e 'opendir(DIR,$ARGV[0]);$n=1000; (-f $_) && copy($_,"$ARGV[1]/$_") while($n-- && readdir(DIR)) 

works for file containing spaces, quotes, etc., which tend to break shell-based solutions (short of $IFS contortions). 'Course if your file names are behaved, shell is fine.

Edit: added check for copying only files.