Как переместить 100 файлов из папки, содержащей тысячи?


43

У меня есть каталог с тысячами файлов. Как я могу переместить 100 файлов (любые файлы будут делать) в другое место.


Поскольку у Unix и Linux нет одного большого веб-сайта о его инструментах, поэтому я просто захожу на веб-сайт, как about.comи на какой-то другой веб-сайт, чтобы получить список доступных опций, которые я могу использовать ... но не нашел ничего подобногоtail
gaijin

Ответы:


36
for file in $(ls -p | grep -v / | tail -100)
do
mv $file /other/location
done

Это предполагает , что имена файлов не содержат пробелы, символы новой строки (предполагается , что значение по умолчанию $IFS), подстановочные символы ( ?, *, [) или начать с -.


12
Обратите внимание, что этот подход работает только в том случае, если в именах файлов нет специальных символов (пробелы, непечатаемые символы, ``). Как правило, не анализируйте выводls . И всегда двойные кавычки параметров и командных подстановок.
Жиль "ТАК - перестань быть злым"

1
На какую часть приходится 100 файлов?
Чепанг

3
Обновление до моего предыдущего комментария: После прочтения ссылочной ссылки Жиля, не анализируйте вывод ls , я обнаружил, что моей findкоманде не хватало. Аргумент был в неправильном месте, и я добавил нулевые окончания имени файла. Это немного длинная строка, но это все, что я могу сделать в комментарии. Вот исправленный фрагмент:find . -maxdepth 1 -type f \( ! -iname ".*" \) -print0 | while read -rd $'\0' file ; do mv -- "$file" /other/location/ ; done
Peter.O

@perer Как примечание, эта read -dопция не переносится на все оболочки, но если вы используете ее в bashлюбом случае, -d ''вы получите тот же эффект, что и -d $'\0'.
jw013

FWIW, если вы хотите, чтобы это запускалось как одиночный, добавьте туда, ;где сейчас находится каждая новая строка .
Патрик

37

Это проще всего в Zsh:

mv -- *([1,100]) /other/location/

При этом перемещаются первые 100 не скрытых файлов (любого типа, изменяются ([1,100])только (.[1,100])на обычные файлы или (^/[1,100])для любого типа, кроме каталога ) в лексикографическом порядке имен. Вы можете выбрать другой порядок сортировки с помощью o квалификатора glob , например, чтобы переместить 100 самых старых файлов:

mv -- *(Om[1,100]) /other/location/

С другими оболочками вы можете сделать это в цикле с ранним выходом.

i=0
for x in *; do
  if [ "$i" = 100 ]; then break; fi
  mv -- "$x" /other/location/
  i=$((i+1))
done

Другой переносимый способ - создать список файлов и удалить все, кроме последних 100 .


+1 для безопасного расширения оболочки. Также будет более читабельным с операцией увеличения $(( i++ ))или $[ i++ ]?

2
@hesse Некоторые оболочки не реализуются ++и --. Вы можете написать : $((i+=1))вместо i=$((i+1)); Я не уверен, что это более читабельно.
Жиль "ТАК - перестань быть злым"

1
:-D, я на самом деле редактировал этот ответ, думая, что это мой ... Извините. Не стесняйтесь вернуться, поскольку это меняет смысл.
Стефан Шазелас

@ StéphaneChazelas Мне интересно, почему вы исключили каталоги и символические ссылки, в этом вопросе ничего не сказано.
Жиль "ТАК - перестань быть злым"

@ Жиль, принятый ответ ls -p | grep -v /так же, как и недавний вопрос, который возникает здесь.
Стефан Шазелас

8

Если вы не используете zsh:

set -- *
[ "$#" -le 100 ] || shift "$(($# - 100))"
mv -- "$@" /target/dir

Переместил бы последние (в алфавитном порядке) 100 единиц.


4

Следующее сработало для меня. Извините, если он был опубликован ранее, но я не увидел его в быстром сканировании.

ls path/to/dir/containing/files/* | head -100 | xargs -I{} cp {} /Path/to/new/dir

3

Следующий oneliner в оболочке поможет.

foreach i (`find Source_Directory -type f --max-deep 1 | tail -100`); делать; {mv $ i Target_Directory}; сделанный

1
Что это за оболочка?
августа

@phk, это может сработать, zshдаже если на первый взгляд это выглядит совершенно чуждо zshсинтаксису. Жиль показал гораздо более простой способ сделать это zsh. Даже тогда, это все еще более надежно, чем принятый в настоящее время ответ.
Стефан Шазелас


1

mmv - выдающаяся утилита, которая также позволит вам делать массовые переименования файлов. (Мне пришлось sudo apt-get install mmvустановить его на своем компьютере.) Простой пример использования: предположим, у вас есть каталог файлов с расширением .JPG, который вы хотите изменить на строчный .jpg. Следующая команда добивается цели:

mmv \*.JPG \#1.jpg

Обратная косая черта используется для обозначения подстановочного знака. * / JPG соответствует чему-либо с расширением JPG. В части «to» команды # 1 использует соответствующий текст из первого подстановочного знака для переименования файла. Конечно, вы можете поставить другой путь перед # 1, чтобы также переместить файл.


2
Было бы более полезно, если бы вы указали, как вы на самом деле будете использовать инструмент, который вы предлагаете для достижения цели.
Дейсон

1
добавил пример использования
Пит

1
#!/bin/bash
c=1; d=1; mkdir -p NEWDIR_${d}
for jpg_file in *.jpg
do
if [ $c -eq 100 ]
then
d=$(( d + 1 )); c=0; mkdir -p NEWDIR_${d}
fi
mv "$jpg_file" NEWDIR_${d}/
c=$(( c + 1 ))
done

попробуй этот код


1

Следующая команда работает, если вы заинтересованы в использовании ls

$ ls -rt source/* | head -n100 | xargs cp -t destination

Как это работает ??

  • ls -rt source/* - команда выводит список всех файлов с относительным путем
  • head -n100 - занимает первые 100 файлов
  • xargs cp -t destination - перемещает эти файлы в папку назначения

0

Попробуй это:

find /source/directory -type f -maxdepth 1 -print | tail -100 | xargs -J % mv % /other/location/

Это неверно, вы передаете три аргумента mv, последний из которых (вероятно) не является каталогом. И это на самом деле не отвечает на вопрос - спрашивающий хочет переместить заданное количество файлов, а не все.
Мат

Команда обновлена.
Saumil

0

Я пришел сюда, но мне нужно было копировать файлы по частям (по 99) /DIR1в /DIR2. Я вставлю сценарий сюда, чтобы помочь другим, может быть:

#!/bin/bash
# Thanks to <Jordan_U> @ #ubuntu
# 06 Dec 2014

i=0
copy_unit=98

for file in /DIR1/*; do
  cp "$file" /DIR2
  if [[ "$i" -ge "$copy_unit" ]]; then
    echo "Pausing, press enter to continue"
    read
    i=0
  fi
  ((i++))
done

0

Если вы хотите быть в безопасности / обрабатывать имена файлов с пробелами, символами новой строки, кавычками, обратной косой чертой и т. Д., Вы должны использовать разделители с нулевым символом в конце:

find "$srcdir" -maxdepth 1 -type f -print0 | head -z -n 100 | xargs -0 -r -- mv -t "$destdir" --

EDIT2: Примечание: если у вас нет head -z( по любой причине ) , вы можете заменить выше head -z -n 1000с tr '\0\n' '\n\0' | head -n 1000 | tr '\0\n' '\n\0'(или увидеть другие способы )

-maxdepth 1не будет искать файлы в подкаталогах $srcdir, поэтому в списке указаны только файлы $srcdir.
-print0будет использовать \0вместо newline ( \n) между каждым перечисленным файлом - это помогает обрабатывать файлы, содержащие символы новой строки и пробелы с xargs.
head -zбудет считать \0завершенные (вместо newline ( \n) прекращенные) строки как строки. -n 100будет перечислять только первые найденные 100файлы find.
Если вы хотите увидеть, какая команда xargsбудет выполняться, добавьте -t(или --verbose).
xargs -0«Элементы ввода завершаются символом null ( \0) вместо пробела, а кавычки и обратный слеш не являются специальными (каждый символ воспринимается буквально)»
xargs -rне будет запускатьсяmvесли нет файлов для перемещения (т. е. если findне найдено ни одного файла).
--прекращает обработку аргументов как опций для программы, подробнее здесь

Пример вывода (запускает одну mvкоманду и может обрабатывать файлы с символами новой строки в их имени):

$ find /tmp/t -maxdepth 1 -type f -print0 | head -z -n 100 | xargs -t -0 -r -- mv -t /tmp -- ; echo "exit codes: ${PIPESTATUS[@]}"
mv -t /tmp -- /tmp/t/file containing quotes"' then spaces /tmp/t/file containing quotes"' /tmp/t/file containing a slash n here\n /tmp/t/file containing a new line here
and continues /tmp/t/s /tmp/t/-x and -L 1. /tmp/t/of replace-str in the initi /tmp/t/-thisfile_starts_with_a_hyphen and has spaces and a -hyphen here /tmp/t/-thisfile_starts_with_a_hyphen and has spaces /tmp/t/-thisfile_starts_with_a_hyphen /tmp/t/another      with       spaces /tmp/t/one with spaces /tmp/t/c /tmp/t/a 
exit codes: 0 0 0

$ ls -1R /tmp/t
/tmp/t:
a
'another      with       spaces'
b
c
'file containing a new line here'$'\n''and continues'
'file containing a slash n here\n'
'file containing quotes"'\'''
'file containing quotes"'\'' then spaces'
'of replace-str in the initi'
'one with spaces'
s
'some dir'
-thisfile_starts_with_a_hyphen
'-thisfile_starts_with_a_hyphen and has spaces'
'-thisfile_starts_with_a_hyphen and has spaces and a -hyphen here'
'-x and -L 1.'

/tmp/t/b:
'file with spaces'

'/tmp/t/some dir':
'some file'

Для find:

-maxdepth levels
       Descend at most levels (a non-negative integer) levels of direc‐
       tories below the starting-points.  -maxdepth 0
        means only apply the tests and actions to  the  starting-points
       themselves.
-type c
       File is of type c:

       b      block (buffered) special

       c      character (unbuffered) special

       d      directory

       p      named pipe (FIFO)

       f      regular file

       l      symbolic link; this is never true if the -L option or the
              -follow  option is in effect, unless the symbolic link is
              broken.  If you want to search for symbolic links when -L
              is in effect, use -xtype.

       s      socket

       D      door (Solaris)
-P     Never follow symbolic links.  This  is  the  default  behaviour.
       When find examines or prints information a file, and the file is
       a symbolic link, the information used shall be  taken  from  the
       properties of the symbolic link itself.
-L     Follow symbolic links.  When find examines or prints information
       about files, the information used shall be taken from the  prop‐
       erties  of  the file to which the link points, not from the link
       itself (unless it is a broken symbolic link or find is unable to
       examine  the file to which the link points).  Use of this option
       implies -noleaf.  If you later use the -P option,  -noleaf  will
       still  be  in  effect.   If -L is in effect and find discovers a
       symbolic link to a subdirectory during its search, the subdirec‐
       tory pointed to by the symbolic link will be searched.

       When the -L option is in effect, the -type predicate will always
       match against the type of the file that a symbolic  link  points
       to rather than the link itself (unless the symbolic link is bro‐
       ken).  Actions that can cause symbolic links  to  become  broken
       while  find  is executing (for example -delete) can give rise to
       confusing behaviour.  Using -L causes  the  -lname  and  -ilname
       predicates always to return false.

Для head:

-n, --lines=[-]NUM
       print the first NUM lines instead of  the  first  10;  with  the
       leading '-', print all but the last NUM lines of each file
-z, --zero-terminated
       line delimiter is NUL, not newline

РЕДАКТИРОВАТЬ: Кто-то упомянул, что у них не было head -z, это версия, которую я использовал (в Fedora 25):

$ head --version
head (GNU coreutils) 8.25
Copyright (C) 2016 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Written by David MacKenzie and Jim Meyering.

$ rpm -qf /usr/bin/head
coreutils-8.25-17.fc25.x86_64

Для xargs:

-0, --null
       Input  items  are  terminated  by a null character instead of by
       whitespace, and the quotes and backslash are not special  (every
       character is taken literally).  Disables the end of file string,
       which is treated like any other  argument.   Useful  when  input
       items  might  contain  white space, quote marks, or backslashes.
       The GNU find -print0 option produces  input  suitable  for  this
       mode.
-r, --no-run-if-empty
       If the standard input does not contain any nonblanks, do not run
       the command.  Normally, the command is run once even if there is
       no input.  This option is a GNU extension.
-P max-procs, --max-procs=max-procs
       Run  up  to max-procs processes at a time; the default is 1.  If
       max-procs is 0, xargs will run as many processes as possible  at
       a  time.   Use the -n option or the -L option with -P; otherwise
       chances are that only one exec will be  done.   While  xargs  is
       running,  you  can send its process a SIGUSR1 signal to increase
       the number of commands to run simultaneously, or  a  SIGUSR2  to
       decrease  the number.  You cannot increase it above an implemen‐
       tation-defined limit (which is shown with  --show-limits).   You
       cannot  decrease  it  below  1.  xargs never terminates its com‐
       mands; when asked to decrease, it merely waits for more than one
       existing command to terminate before starting another.

       Please  note  that  it is up to the called processes to properly
       manage parallel access to shared  resources.   For  example,  if
       more  than one of them tries to print to stdout, the ouptut will
       be produced in an indeterminate order (and very likely mixed up)
       unless  the  processes  collaborate in some way to prevent this.
       Using some kind of locking scheme is one  way  to  prevent  such
       problems.   In  general, using a locking scheme will help ensure
       correct output but reduce performance.  If  you  don't  want  to
       tolerate  the  performance  difference,  simply arrange for each
       process to produce a separate output file (or otherwise use sep‐
       arate resources).
-t, --verbose
       Print  the command line on the standard error output before exe‐
       cuting it.

Для cp:

-t, --target-directory=DIRECTORY
       copy all SOURCE arguments into DIRECTORY
-v, --verbose
       explain what is being done

0

Еще один вариант, вдохновленный https://unix.stackexchange.com/a/105042/66736 :

cp `ls -d ./* | head -n 100` tmpi

Это может быть не самый быстрый или самый элегантный способ, но это способ, который вы можете сохранить в памяти.


-2

Я знаю, что эта ветка довольно старая, но я нашел ответы более сложными, чем я думал, что они должны быть. Это сработало в CentOS, но кажется достаточно простым, чтобы оно могло работать в других дистрибутивах.

cp `ls someDir | head -n 100` someDir100/

1
Это не работает, потому что вывод lsне будет содержать somedir/начальный префикс, и не будет работать для имени файла с пустыми или подстановочными символами или начинаться с -.
Стефан Шазелас

Справедливо. Я на самом деле сделал cp ls | head -n 100../someDir100/ из целевого каталога, и ни одно из имен файлов не удовлетворяло этим случаям. Лучше быть удачливым, чем хорошим!
Джейсон
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.