Решение «mv: Список аргументов слишком длинный»?

У меня есть папка с более чем миллионом файлов, которые требуют сортировки, но я ничего не могу сделать, потому что mv выводит это сообщение все время

 -bash: /bin/mv: Argument list too long 

Я использую эту команду для перемещения файлов без расширения:

 mv -- !(*.jpg|*.png|*.bmp) targetdir/ 

  • Почему MV (1) копирует объекты, если разрешение на перенос отклонено?
  • Mac: самый простой способ перемещения нескольких дубликатов имен файлов в один каталог
  • Сломанные файлы после перемещения их назад и вперед
  • Почему требуются разрешения на выполнение для переименования файлов в каталоге?
  • Как права на каталоги остаются такими же после команды mv?
  • как переместить много подпапок в родительский каталог?
  • Как вы можете перемещать или копировать определенные файлы из списка текстовых файлов
  • mv: перемещать файл только в том случае, если адресата не существует
  • 5 Solutions collect form web for “Решение «mv: Список аргументов слишком длинный»?”

    xargs – это инструмент для работы. Это, или find с -exec … {} + . Эти инструменты запускают команду несколько раз, с таким количеством аргументов, которые могут быть переданы за один раз.

    Оба метода легче выполнять, когда список переменных аргументов находится в конце, что здесь не так: конечным аргументом для mv является назначение. С утилитами GNU (например, на не встроенных Linux или Cygwin) опция -t для mv полезна, чтобы перенести пункт назначения в первую очередь.

    Если имена файлов не имеют пробелов или ни одного из \"' , то вы можете просто предоставить имена файлов в качестве входных данных для xargs (команда echo является встроенной bash, поэтому она не подпадает под ограничение длины командной строки):

     echo !(*.jpg|*.png|*.bmp) | xargs mv -t targetdir 

    Вы можете использовать параметр -0 для xargs для использования xargs с нулевым ограничением вместо стандартного котируемого формата.

     printf '%s\0' !(*.jpg|*.png|*.bmp) | xargs -0 mv -t targetdir 

    Кроме того, вы можете сгенерировать список имен файлов с помощью find . Чтобы избежать рекурсии в подкаталоги, используйте -type d -prune . Поскольку для перечисленных файлов изображений не указано действие, переносятся только другие файлы.

     find . -name . -o -type d -prune -o \ -name '*.jpg' -o -name '*.png' -o -name '*.bmp' -o \ -exec mv -t targetdir/ {} + 

    (Сюда входят файлы точек, в отличие от подстановочных методов оболочки.)

    Если у вас нет утилит GNU, вы можете использовать промежуточную оболочку для получения аргументов в правильном порядке. Этот метод работает на всех POSIX-системах.

     find . -name . -o -type d -prune -o \ -name '*.jpg' -o -name '*.png' -o -name '*.bmp' -o \ -exec sh -c 'mv "$@" "$0"' targetdir/ {} + 

    В zsh вы можете загрузить mv builtin :

     setopt extended_glob zmodload zsh/files mv -- ^*.(jpg|png|bmp) targetdir/ 

    или если вы хотите, чтобы mv и другие имена ссылались на внешние команды:

     setopt extended_glob zmodload -Fm zsh/files b:zf_\* zf_mv -- ^*.(jpg|png|bmp) targetdir/ 

    или с шагами в стиле ksh:

     setopt ksh_glob zmodload -Fm zsh/files b:zf_\* zf_mv -- !(*.jpg|*.png|*.bmp) targetdir/ 

    В качестве альтернативы, используя GNU mv и zargs :

     autoload -U zargs setopt extended_glob zargs -- ./^*.(jpg|png|bmp) -- mv -t targetdir/ 

    Ограничение прохождения аргумента операционной системы не распространяется на расширения, которые происходят в интерпретаторе оболочки. Поэтому, помимо использования xargs или find , мы можем просто использовать цикл оболочки, чтобы разбить обработку на отдельные команды mv :

     for x in *; do case "$x" in *.jpg|*.png|*.bmp) ;; *) mv -- "$x" target ;; esac ; done 

    В нем используются только функции и утилиты командной строки командной оболочки POSIX. Этот однострочный ящик более четкий с отступом, с ненужными точками с запятой удалены:

     for x in *; do case "$x" in *.jpg|*.png|*.bmp) ;; # nothing *) # catch-all case mv -- "$x" target ;; esac done 

    Для более агрессивного решения, чем предлагаемые ранее, include/linux/binfmts.h исходный код ядра и отредактируйте include/linux/binfmts.h

    Увеличьте размер MAX_ARG_PAGES до чего-то большего, чем 32. Это увеличит объем памяти, который ядро ​​будет использовать для аргументов программы, тем самым вы сможете указать команду mv или rm для миллиона файлов или того, что вы делаете. Перекомпилируйте, установите, перезагрузите компьютер.

    BEWARE! Если вы установите слишком большое значение для вашей системной памяти, а затем запустите команду с большим количеством аргументов. ПЛОХИЕ ВЕЩИ БУДУТ СЛУЧИЛИСЬ! Будьте предельно осторожны, делая это для многопользовательских систем, это позволяет злоумышленникам использовать всю вашу память!

    Если вы не знаете, как перекомпилировать и переустановить ваше ядро ​​вручную, вероятно, лучше всего, что вы просто притворяетесь, что этого ответа пока не существует.

    Более простое решение, использующее "$origin"/!(*.jpg|*.png|*.bmp) вместо блока catch:

     for file in "$origin"/!(*.jpg|*.png|*.bmp); do mv -- "$file" "$destination" ; done 

    Благодаря @Score_Under

    Для многострочного скрипта вы можете сделать следующее (обратите внимание на ; до того, как done будет удалено):

     for file in "$origin"/!(*.jpg|*.png|*.bmp); do # don't copy types *.jpg|*.png|*.bmp mv -- "$file" "$destination" done 

    Чтобы сделать более обобщенное решение, которое перемещает все файлы, вы можете сделать однострочный:

     for file in "$origin"/*; do mv -- "$file" "$destination" ; done 

    Это выглядит так, если вы выполните отступы:

     for file in "$origin"/*; do mv -- "$file" "$destination" done 

    Это берет каждый файл в начале и перемещает их один за другим в пункт назначения. Котировки вокруг $file необходимы в случае, если в $file есть пробелы или другие специальные символы.

    Вот пример этого метода, который отлично работал

     for file in "/Users/william/Pictures/export_folder_111210/"*.jpg; do mv -- "$file" "/Users/william/Desktop/southland/landingphotos/"; done 

    Вы можете обойти это ограничение при использовании mv если вы не пропустите его пару раз.

    Вы можете перемещать порции за раз. Скажем, например, у вас был длинный список буквенно-цифровых имен файлов.

     mv ./subdir/a* ./ 

    Это работает. Затем выбейте еще один большой кусок. После пары шагов вы можете просто вернуться к использованию mv ./subdir/* ./

    Linux и Unix - лучшая ОС в мире.