Подтвердить что ты не робот

Когда следует использовать xargs по сравнению с циклами while-read?

xargs широко используется в сценариях оболочки; обычно легко переделать эти использования в bash, используя циклы while read -r; do ... done или while read -ar; do ... done.

Когда следует xargs быть предпочтительным, а когда должны быть предпочтительны циклы while-read?

4b9b3361

Ответ 1

Вещью с циклами while является то, что они имеют тенденцию обрабатывать один элемент за раз, часто, когда это не нужно. Здесь xargs имеет преимущество - он может выставлять аргументы, чтобы одна команда обрабатывала множество элементов.

Например, цикл while:

pax> echo '1
2
3 
4
5' | while read -r; do echo $REPLY; done
1
2
3
4
5

и соответствующий xargs:

pax> echo '1
2
3 
4
5' | xargs echo
1 2 3 4 5

Здесь вы можете видеть, что строки обрабатываются один за другим с помощью while и всего с xargs. Другими словами, первая эквивалентна echo 1 ; echo 2 ; echo 3 ; echo 4 ; echo 5, а последняя эквивалентна echo 1 2 3 4 5 (пять процессов, в отличие от одного). Это действительно имеет значение при обработке тысяч или десятков тысяч строк, поскольку создание процесса требует времени.

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

Когда я обрабатываю небольшие файлы или команды для запуска на каждом элементе сложны (где мне слишком ленив написать отдельный script, чтобы дать xargs), я буду использовать вариант while.

Где меня интересует производительность (большие файлы), я буду использовать xargs, даже если мне нужно написать отдельный script.

Ответ 2

"xargs" имеют параметр "-n max-args", который, как я полагаю, позволит сразу вызвать команду для нескольких аргументов (полезно для "grep", "rm" и многих других таких программ) Попробуйте пример из man-страницы:

cut -d: -f1 < /etc/passwd | sort | xargs -n 5 echo

И вы увидите, что он "эхо" - по 5 пользователей в строке

P.S. И не забывайте, что "xargs" - это программа (например, подоболочка). Таким образом, вы не можете легко получить информацию в своей оболочке script (вам нужно будет прочитать выходные данные ваших "xargs" и каким-то образом интерпретировать ваши оболочки/env-переменные).

Ответ 3

Некоторые реализации xargs также понимают аргумент -P MAX-PROCS, который позволяет xargs выполнять несколько заданий параллельно. Это было бы довольно сложно смоделировать с помощью цикла while read.

Ответ 4

GNU Parallel http://www.gnu.org/software/parallel/ имеет преимущества от xargs (с использованием -m) и преимущества while-read с новой строкой как разделитель и некоторые новые функции (например, группировка вывода, параллельное выполнение заданий на удаленных компьютерах и замена контекста).

Если у вас установлен GNU Parallel, я не вижу ни одной ситуации, в которой вы бы использовали xargs. И единственная ситуация, в которой я бы использовал read-while, была бы, если бы блок для выполнения был настолько велик, что он становится нечитаемым, чтобы помещать в одну строку (например, если он содержит if-statements или аналогичный), и вы отказываетесь от создания bash.

Для всех небольших скриптов я нахожу его более читаемым для использования GNU Parallel. Пример paxdiablo:

echo '1
2
3 
4
5' | parallel -m echo

Преобразование WAV файлов в MP3 с использованием GNU Параллель:

find sounddir -type f -name '*.wav' | parallel -j+0 lame {} -o {.}.mp3

Смотрите видеоролик для GNU Parallel: http://www.youtube.com/watch?v=OpaiGYxkSuQ

Ответ 5

Напротив, бывают случаи, когда у вас есть список файлов, по 1 на строку, содержащий пробелы. Например. начиная с find или pkgutil или аналогичного. Для работы с xargs сначала вам придется обернуть строки в кавычках, используя sed, но это выглядит громоздким.

С циклом while script может показаться легче читать/писать. И цитирование пространственно-загрязненных аргов тривиально. Пример ниже является искусственным, но представьте, что вы получаете список файлов из чего-то другого, кроме find...

function process {
  while read line; do
    test -d "$line" && echo "$line"
  done
}

find . -name "*foo*" | process

Ответ 6

Я не понимаю, люди продолжают рыться о том, как в то время как ДОЛЖНО выполняться в цикле, а не за пределами цикла. Я знаю очень мало на стороне Linux, но я знаю, что довольно просто использовать переменные MS-DOS для создания списка параметров, или > file, cmd < файл для создания списка параметров, если вы превысите ограничение длины строки.

Или люди говорят, что linux не так хорош, как ms-dos? (Черт, я ЗНАЮ, что вы можете строить цепочки, потому что многие скрипты bash, очевидно, делают это, просто не в циклах).

В этот момент это становится вопросом ограничений/предпочтений ядра. xargs не волшебный; у трубопроводов есть преимущества перед строковым построением (ну, ms-dos, вы можете построить строку из "указателей" и избежать копирования (это виртуальная память в конце концов, если вы не изменяете данные, вы можете пропустить расход в строке concat... но трубопровод - более родная поддержка)). На самом деле, я не думаю, что могу дать ему преимущество параллельной обработки, потому что вы можете легко создать несколько заданных циклов для просмотра разрезанных данных (что опять же, если вы избегаете копирования, это очень быстрое действие).

В конце концов, xargs больше подходит для встроенных команд, преимущество в скорости невелико (разница между скомпилированным/интерпретируемым строковым строением), потому что все, что он делает, вы можете выполнять с помощью сценариев оболочки.