У меня есть папка с более чем миллионом файлов, которые нужно отсортировать, но я ничего не могу сделать, потому что mv
выводит это сообщение постоянно
-bash: /bin/mv: Argument list too long
Я использую эту команду для перемещения файлов без расширений:
mv -- !(*.jpg|*.png|*.bmp) targetdir/
Ответы:
xargs
это инструмент для работы. Это илиfind
с-exec … {} +
. Эти инструменты запускают команду несколько раз, используя столько аргументов, сколько можно передать за один раз.Оба метода проще выполнить, когда список аргументов переменной находится в конце, а здесь это не так: последний аргумент to
mv
- это пункт назначения. Для утилит GNU (т. Е. Для не встроенных Linux или Cygwin) полезна-t
опция tomv
, чтобы сначала передать пункт назначения.Если имена файлов не имеют ни пробелов, ни каких-либо из них
\"'
, вы можете просто предоставить имена файлов в качестве входных данныхxargs
(echo
команда является встроенной в bash, поэтому она не подпадает под ограничение длины командной строки):Вы можете использовать
-0
опцию, чтобыxargs
использовать ввод с нулем в качестве разделителя вместо формата по умолчанию в кавычках.Кроме того, вы можете создать список имен файлов с помощью
find
. Чтобы избежать повторного использования в подкаталогах, используйте-type d -prune
. Поскольку для перечисленных файлов изображений не указано никаких действий, перемещаются только другие файлы.(Это включает файлы точек, в отличие от методов подстановки оболочки.)
Если у вас нет утилит GNU, вы можете использовать промежуточную оболочку, чтобы получить аргументы в правильном порядке. Этот метод работает во всех системах POSIX.
В zsh вы можете загрузить
mv
встроенное :или если вы предпочитаете, чтобы
mv
другие имена продолжали ссылаться на внешние команды:или с шариками в стиле ksh:
В качестве альтернативы, используя GNU
mv
иzargs
:источник
shopt -s extglob
будет включить его. Я пропустил шаг вfind
командах, я исправил их.find
Команды, которые я опубликовал (сейчас), работают. Вы должны были оставить часть при вставке копии.!
? Это более явно и легче понять, чем странный трейлинг-o
. Например,! -name '*.jpg' -a ! -name '*.png' -a ! -name '*.bmp'
Если работы с ядром Linux достаточно, вы можете просто
это будет работать, потому что ядро Linux включило исправление около 10 лет назад, которое изменило лимит аргументов в зависимости от размера стека: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/ фиксация /? ID = b6a2fea39318e43fee84fa7b0b90d68bed92d2ba
Обновление: если вы чувствуете себя смелым, вы можете сказать,
и вы будете в порядке с любыми расширениями оболочки, если у вас достаточно оперативной памяти.
источник
ulimit -s unlimited
его, и он будет работать практически с неограниченным количеством файлов.ulimit -s unlimited
фактической командной строке ограничение составляет 2 ^ 31 или 2 ГБ. (MAX_ARG_STRLEN
в исходном коде ядра.)Предел передачи аргументов операционной системы не распространяется на расширения, которые происходят внутри интерпретатора оболочки. Поэтому в дополнение к использованию
xargs
илиfind
мы можем просто использовать цикл оболочки, чтобы разбить обработку на отдельныеmv
команды:При этом используются только функции и утилиты POSIX Shell Command Language. Этот однострочник более понятен с отступом, удалив ненужные точки с запятой:
источник
mv
процессов, а не только нескольких, необходимых для использованияfind
решения POSIX, опубликованного @Gilles. Другими словами, этот способ приводит к большому количеству ненужного оттока процессора.case
утверждение о результате*
расширения для фильтрации нескольких расширений эквивалентно исходному!(*.jpg|*.png|*.bmp)
выражению.find
Ответ на самом деле не эквивалентны; он спускается в подкаталоги (я не вижу-maxdepth
предиката).-name . -o -type d -prune -o
защищает от спуска в подкаталоги.-maxdepth
очевидно, не POSIX-совместимый, хотя это не упоминается на моейfind
странице руководства.Для более агрессивного решения, чем предложенные ранее, откройте исходный код ядра и отредактируйте
include/linux/binfmts.h
Увеличьте размер
MAX_ARG_PAGES
до значения, превышающего 32. Это увеличивает объем памяти, который ядро будет предоставлять программным аргументам, что позволит вам указать вашу командуmv
илиrm
команду для миллиона файлов или что бы вы ни делали. Перекомпилируйте, установите, перезагрузите компьютер.BEWARE! Если вы установите это значение слишком большим для вашей системной памяти, а затем запустите команду с большим количеством аргументов, БАДОВЫЕ ВЕЩИ БУДУТ! Будьте предельно осторожны, делая это с многопользовательскими системами, так как злоумышленникам будет проще использовать всю вашу память!
Если вы не знаете, как перекомпилировать и переустановить ядро вручную, вероятно, лучше всего сделать вид, что этого ответа пока не существует.
источник
Более простое решение, использующее
"$origin"/!(*.jpg|*.png|*.bmp)
вместо блока catch:Благодаря @Score_Under
Для многострочного сценария вы можете сделать следующее (обратите внимание на то, что
;
передdone
удалением):Чтобы сделать более обобщенное решение, которое перемещает все файлы, вы можете сделать одну строку:
Который выглядит так, если вы делаете отступ:
Это берет каждый файл в источнике и перемещает их один за другим к месту назначения. Кавычки
$file
необходимы, если в именах файлов есть пробелы или другие специальные символы.Вот пример этого метода, который работал отлично
источник
!(*.jpg|*.png|*.bmp)
. Вы можете добавить это к своему циклу for, используя глобализацию,"$origin"/!(*.jpg|*.png|*.bmp)
которая позволит избежать необходимости использования переключателя, используемого в ответе Kaz, и сохранит простое тело цикла for.Иногда проще всего написать небольшой скрипт, например, на Python:
источник
Вы можете обойти это ограничение, все еще используя его,
mv
если не возражаете против его запуска пару раз.Вы можете перемещать порции за раз. Допустим, например, у вас был длинный список буквенно-цифровых имен файлов.
Это работает. Затем выбейте еще один большой кусок. После пары движений вы можете просто вернуться к использованию
mv ./subdir/* ./
источник
Вот мои два цента, добавьте это в
.bash_profile
использование
источник