Решение “mv: Список аргументов слишком долго”?

0)

lii0 is the WAN interface

1)

echo "up" > /etc/hostname.lii0

2)

vi /etc/hostname.pppoe0 
inet 0.0.0.0 255.255.255.255 NONE \
pppoedev lii0 authproto pap \
authname 'PPPOEUSERNAME' authkey 'PPPOEPASSWORD' up
dest 0.0.0.1
!/sbin/route add default -ifp pppoe0 0.0.0.1

3)

sh /etc/netstart
65
17.09.2016, 18:08
8 ответов

xargs

- инструмент для выполнения задания. Это, или

найти

с помощью [116173]-exec ... {} +[116174]. Эти инструменты запускают команду несколько раз, с максимальным количеством аргументов, которое может быть передано за один раз.

Оба метода проще выполнить, когда список переменных аргументов находится в конце, что здесь не так: конечным аргументом для [116175]mv[116176] является назначение. С утилитами GNU (например, на не встраиваемых Linux или Cygwin) вариант [116177]-t[116178] для [116179]mv[116180] полезен, чтобы сначала передать пункт назначения.

Если имена файлов не имеют ни белого пробела, ни любого из [116181]\"''[116182], то вы можете просто указать имена файлов на входе в [116183]xargs[116184] (команда [116185]echo[116186] является bash builtin, так что на нее не распространяется ограничение длины командной строки):

Вы можете использовать опцию [116187]-0[116188] для [116189]xargs[116190], чтобы использовать ввод с нулевым делением вместо формата по умолчанию, заданного в кавычках.

В качестве альтернативы вы можете сгенерировать список имен файлов с помощью [116191]find[116192]. Чтобы избежать повторения в подкаталогах, используйте [116193]-тип d -prune[116194]. Так как для перечисленных файлов изображений не указано никаких действий, перемещаются только остальные файлы.

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

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

В zsh можно загрузить

mv[116508] builtin[116196]:

или, если вы предпочитаете, чтобы [116197]mv[116198] и другие имена продолжали ссылаться на внешние команды: или с помощью глобусов в стиле ksh-: Альтернативно, используя GNU [116199]mv[116200] и zargs :

85
27.01.2020, 19:32

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

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

Это использует только возможности и утилиты командного языка POSIX Shell. Этот один лайнер понятнее с отступом, при этом удаляются ненужные точки с запятой:

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

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

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

ОСТОРОЖНО! Если вы установите это значение слишком большим для вашей системной памяти, а затем запустите команду с большим количеством аргументов, БУДУТ ПЛОХОЕ! Будьте предельно осторожны, делая это в многопользовательских системах, так злоумышленникам будет проще использовать всю вашу память!

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

5
27.01.2020, 19:32

Более простое решение с использованием "$ 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 необходимы в случае, если в именах файлов есть пробелы или другие специальные символы.

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

for file in "/Users/william/Pictures/export_folder_111210/"*.jpg; do
    mv -- "$file" "/Users/william/Desktop/southland/landingphotos/";
done
5
27.01.2020, 19:32

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

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

mv ./subdir/a* ./

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

1
27.01.2020, 19:32

Если работы с ядром Linux достаточно, вы можете просто сделать

ulimit -S -s unlimited

Это сработает, потому что около 10 лет назад ядро ​​Linux включало исправление, которое изменило лимит аргументов, чтобы он основывался на размере стека:https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=b6a2fea39318e43fee84fa7b0b90d68bed92d2ba

Если вам не нужно неограниченное пространство стека, вы можете сказать, например,.

ulimit -S -s 100000

, чтобы ограничить стек до 100 МБ. Обратите внимание, что вам нужно установить пространство стека для нормального использования стека (, обычно 8 МБ )плюс размер командной строки, которую вы хотели бы использовать.

Вы можете запросить фактическое ограничение следующим образом:

getconf ARG_MAX

, который выведет максимальную длину командной строки в байтах. Например, по умолчанию в Ubuntu установлено значение 2097152, что означает примерно 2 МБ. Если я работаю с неограниченным стеком, я получаю 4611686018427387903, что равно 2 ^ 62 или около 46000 ТБ. Если ваша командная строка превышает по сравнению с , я ожидаю, что вы сможете решить проблему самостоятельно.

35
27.01.2020, 19:32

Иногда проще всего написать небольшой скрипт, например. на Питоне:

import glob, shutil

for i in glob.glob('*.jpg'):
  shutil.move(i, 'new_dir/' + i)
10
27.01.2020, 19:32

Вот мои два цента, добавьте это в.bash_profile

mv() {
  if [[ -d $1 ]]; then #directory mv
    /bin/mv $1 $2
  elif [[ -f $1 ]]; then #file mv
    /bin/mv $1 $2
  else
    for f in $1
    do
      source_path=$f
      #echo $source_path
      source_file=${source_path##*/}
      #echo $source_file
      destination_path=${2%/} #get rid of trailing forward slash

      echo "Moving $f to $destination_path/$source_file"

      /bin/mv $f $destination_path/$source_file
    done
  fi
}
export -f mv

Использование

mv '*.jpg'./destination/
mv '/path/*'./destination/
0
27.01.2020, 19:32

Теги

Похожие вопросы