Список аргументов слишком длинный для ls при перемещении файлов из одного каталога в другой в оболочке bash - PullRequest
0 голосов
/ 17 октября 2018

Ниже приведена команда, которую я использую для перемещения файлов из каталога dir a в каталог dir b

  ls /<someloc>/a/* | tail -2000 | xargs -I{} mv {} /<someloc>/b/
    -bash: /usr/bin/ls: Argument list too long

* a содержит файлы в миллионах ..

Need yourпомогите исправить это пожалуйста.

Ответы [ 2 ]

0 голосов
/ 17 октября 2018

ls в коде в вопросе не делает ничего полезного.Глоб (/<someloc>/a/*) создает отсортированный список файлов, а ls просто копирует его (после повторной сортировки), если он вообще работает.См. «Список аргументов слишком длинный»: как с ним справиться, не меняя мою команду? по причине сбоя ls.

Один из способов заставить код работатьзаменить ls на printf:

printf '%s\n' /<someloc>/a/* | tail -2000 | xargs -I{} mv {} /<someloc>/b/

printf - встроенная функция Bash, поэтому при ее запуске не создается подпроцесс, и проблема «Список аргументов слишком длинный» не возникает.

Этот код все равно не будет работать, если какой-либо из файлов будет содержать символ новой строки в имени.Смотрите ответ от kvantour для альтернатив, которые не уязвимы для этой проблемы.

0 голосов
/ 17 октября 2018

Если расположение обоих каталогов находится на одном диске / разделе, а папка b изначально пуста, вы можете сделать следующее

$ rmdir /path/to/b
$ mv /other/path/to/a /path/to/b
$ mkdir /other/path/to/a

Если папка b не пуста, то выможет сделать что-то вроде этого:

find /path/to/a/ -type f -exec mv -t /path/to/b {} +

Если вы просто хотите переместить 2000 файлов, вы можете сделать

find /path/to/a/ -type f -print | tail -2000 | xargs mv -t /path/to/b

Но это может быть проблематично с некоторыми именами файлов.Более чистый способ - использовать -print0 из find, но проблема в том, что head и tail не могут их обработать, поэтому для этого нужно использовать awk.

# first 2000 files (mimick head)
find /path/to/a -type f -print0        \
  | awk 'BEGIN{RS=ORS="\0"}(NR<=2000)' \
  | xargs -0 mv -t /path/to/b

# last 2000 files (mimick tail)
find /path/to/a -type f -print0        \
  | awk 'BEGIN{RS=ORS="\0"}{a[NR%2000]=$0}END{for(i=1;i<=2000;++i) print a[i]}' \
  | xargs -0 mv -t /path/to/b
...