62

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
  • 723
  • 1
  • 5
  • 6
  • 1
    What do you mean by "first"? Did you look at [this related question](http://unix.stackexchange.com/questions/12976/how-to-move-100-files-from-a-folder-containing-thousands) ? – 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 that `ls` 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
  • 234,489
  • 66
  • 447
  • 667
onur güngör
  • 1,274
  • 8
  • 14
  • @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`](https://unix.stackexchange.com/revisions/29221/5) 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](https://unix.stackexchange.com/a/467153/306023) 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](https://manpages.debian.org/unstable/coreutils/head.1.en.html) 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.)

Stéphane Chazelas
  • 522,931
  • 91
  • 1,010
  • 1,501
Stéphane Gimenez
  • 28,527
  • 3
  • 76
  • 87
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.

Alien Life Form
  • 621
  • 5
  • 12