Как это исправить?
Вы должны выбрать уникальный разделитель.
echo 'file 1|file 2|file 3' | xargs -d "|" -n1 bash -c 'my_function "$@"' --
echo 'file 1^file 2^file 3' | parallel -d "^" my_function
Самое безопасное - использовать нулевой байт в качестве разделителя:
echo -e 'file 1\x00file 2\x00file 3' | xargs -0 ' -n1 bash -c 'my_function "$@"' --
printf "%s\0" 'file 1' 'file 2' 'file 3' | parallel -0 my_function
Лучше всего хранить ваши элементы в массиве bash и использовать поток, разделенный нулями, для их обработки:
files=("file 1" "file 2" "file 3")
printf "%s\0" "${files[@]}" | xargs -0 -n1 bash -c 'my_function "$@"' --
printf "%s\0" "${files[@]}" | parallel -0 my_function
Обратите внимание, что пустые массивы будут запускать функцию без каких-либо аргументы. Иногда предпочтительно использовать опцию -r
--no-run-if-empty
, чтобы не запускать функцию, когда ввод пуст. --no-run-if-empty
поддерживается parallel
и является расширением GNU в xargs
(xargs
на BSD и на OSX не имеют --no-run-if-empty
).
Примечание: xargs
по умолчанию анализирует '
, "
и \
. Вот почему следующее возможно и будет работать:
echo '"file 1" "file 2" "file 3"' | xargs -n1 bash -c 'my_function "$@"' --
echo "'file 1' 'file 2' 'file 3'" | xargs -n1 bash -c 'my_function "$@"' --
echo 'file\ 1 file\ 2 file\ 3' | xargs -n1 bash -c 'my_function "$@"' --
И это может привести к некоторым странным вещам, поэтому не забывайте почти всегда указывать параметр -d
для xargs
:
$ # note \x replaced by single x
$ echo '\\a\b\c' | xargs
\abc
$ # quotes are parsed and need to match
$ echo 'abc"def' | xargs
xargs: unmatched double quote; by default quotes are special to xargs unless you use the -0 option
$ echo "abc'def" | xargs
xargs: unmatched single quote; by default quotes are special to xargs unless you use the -0 option
xargs
- это портативный инструмент, доступный повсюду, в то время как parallel
- это программа GNU, которую нужно устанавливать отдельно.