GNU parallel
является вариантом xargs
. Они оба имеют очень похожие интерфейсы, и если вам нужна помощь по parallel
, вам может повезти, если вы найдете информацию о xargs
.
Это, как говорится, способ, которым они оба работают, довольно прост. С их поведением по умолчанию обе программы считывают ввод из STDIN, а затем разбивают ввод на токены на основе пробелов. Каждый из этих токенов затем передается в предоставленную программу в качестве аргумента. По умолчанию xargs передает программе как можно больше токенов, а затем запускает новый процесс при достижении предела. Я не уверен, как работает по умолчанию для параллельного.
Вот пример:
> echo "foo bar \
baz" | xargs echo
foo bar baz
Существуют некоторые проблемы с поведением по умолчанию, поэтому часто можно увидеть несколько вариантов.
Первая проблема заключается в том, что из-за того, что для токенизации используются пробелы, любые файлы с пробелами в них приводят к разрыву параллелизма и xargs. Одно из решений - вместо этого использовать токены вокруг символа NULL. find
даже предоставляет возможность сделать это легко:
> echo "Success!" > bad\ filename
> find . "bad\ filename" -print0 | xargs -0 cat
Success!
Опция -print0
указывает find
разделять файлы символом NULL вместо пробела.
Опция -0
указывает xargs
использовать символ NULL для маркировки каждого аргумента.
Обратите внимание, что parallel
немного лучше, чем xargs
в том смысле, что его поведение по умолчанию - это токенизация вокруг только новых строк, поэтому нет необходимости изменять поведение по умолчанию.
Другая распространенная проблема заключается в том, что вы можете контролировать, как аргументы передаются в xargs
или parallel
. Если вам нужно конкретное размещение аргументов, передаваемых программе, вы можете использовать {}
, чтобы указать, где должен располагаться аргумент.
> mkdir new_dir
> find -name *.xml | xargs mv {} new_dir
Это переместит все файлы в текущем каталоге и подкаталогах в каталог new_dir. Это на самом деле распадается на следующее:
> find -name *.xml | xargs echo mv {} new_dir
> mv foo.xml new_dir
> mv bar.xml new_dir
> mv baz.xml new_dir
Итак, учитывая, как работают xargs
и parallel
, вы должны надеяться увидеть проблему с вашей командой. find . -name '*.xml'
создаст список файлов xml, которые будут переданы программе script.sh
.
> find . -name '*.xml' | parallel -j2 echo script.sh {}
> script.sh foo.xml
> script.sh bar.xml
> script.sh baz.xml
Однако ls | parallel -j2 script.sh {}
сгенерирует список ВСЕХ файлов в текущем каталоге для передачи в программу script.sh.
> ls | parallel -j2 echo script.sh {}
> script.sh some_directory
> script.sh some_file
> script.sh foo.xml
> ...
Более правильный вариант для версии ls
будет выглядеть следующим образом:
> ls *.xml | parallel -j2 script.sh {}
Однако, и важное различие между этой и поисковой версией заключается в том, что find будет искать файлы во всех подкаталогах, а ls будет искать только текущий каталог. Эквивалентная find
версия вышеуказанной команды ls
будет выглядеть следующим образом:
> find -maxdepth 1 -name '*.xml'
Это будет искать только текущий каталог.