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

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

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


person Charles Stewart    schedule 04.04.2010    source источник


Ответы (6)


Суть циклов 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 (пять процессов вместо одного). Это действительно имеет значение при обработке тысяч или десятков тысяч строк, поскольку создание процесса требует времени.

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

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

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

person paxdiablo    schedule 04.04.2010
comment
Я знаю, что это старый поток, но я подумал, что могу добавить, что xargs -n1 дает тот же результат, что и цикл while - person bendaizer; 05.02.2013

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

person ndim    schedule 04.04.2010
comment
Просто имейте в виду, что вывод на стандартный вывод нельзя доверять. См. пример: gnu.org/software/parallel/ (параллельный часть grep). - person Ole Tange; 12.08.2014

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

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

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

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

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

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

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

person Ole Tange    schedule 08.07.2010

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

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

И вы увидите, что он "отображает" 5 пользователей в строке.

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

person ony    schedule 04.04.2010

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

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

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

find . -name "*foo*" | process
person Andrey Taranov    schedule 21.01.2015

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

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

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

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

person I don't know    schedule 08.03.2015
comment
Обычно вы не будете использовать ни одну из форм для создания списков в стиле параметров, скорее это потоковая обработка, где преимущество скорости xargs может быть огромным. Bash, среди других оболочек, но не стандартная оболочка POSIX Bourne, позволяет достичь того, что вы описываете, используя массивы. - person Charles Stewart; 18.03.2015