Почему GNU не работает параллельно с «bash -c»?

9
% echo -e '1\n2' | parallel "bash -c 'echo :\$1' '' {}"
:1
:2
% echo -e '1\n2' | parallel bash -c 'echo :\$1' '' {}


%

Я ожидаю, что вторая строка будет действовать так же.

Райтис Вейнбахс
источник

Ответы:

11

parallelзапускает команду в оболочке уже (что оболочка она определяется с parallelпомощью эвристики (намерение в том , чтобы вызвать ту же оболочку , как один parallelбыл вызван из ). Вы можете установить $PARALLEL_SHELLпеременную для фиксации оболочки).

Это не команда, которую вы передаете, parallelкак для команды envor xargs, а командная строка оболочки (как для evalкоманды).

Как eval, например parallel arg1 arg2, parallelобъединяет эти аргументы с пробелами между ними (так становится arg1 arg2) и эта строка передается <the-shell> -c.

Для аргументов, передаваемых в parallelstdin, parallelзаключите их в кавычки в формате, ожидаемом этой конкретной оболочкой (трудная и подверженная ошибкам задача, поэтому вы обнаружите, что было исправлено много ошибок, связанных с этим в parallelChangelog ( некоторые по-прежнему не исправлены по состоянию на 2017-03-06)) и добавляет его в эту командную строку.

Так, например, если вызвано изнутри bash,

echo "foo'bar" | parallel echo foo

Будет ли иметь параллельный вызов bash -cс echo foo foo\'barв командной строке. И если вызвано изнутри rc(или с PARALLEL_SHELL=rc) rc -cс echo foo foo''''bar.

В вашей:

parallel bash -c 'echo :\$1' '' {}

parallel объединяет те аргументы, которые дают:

bash -c echo :$1  {}

А с {}расширенным и заключенным в кавычки в правильном формате для оболочки, из которой вы вызываете parallel, передает то, к <that-shell> -cчему будет вызываться bash -c echoс :$1in, $0и текущий аргумент in $1.

Это не так, как parallelработает. Здесь вы, вероятно, захотите:

printf '1\n2\n' | PARALLEL_SHELL=bash parallel 'echo :{}'

Чтобы увидеть, что parallelделает, вы можете запустить его в strace -fe execve(или эквивалент в вашей системе, если не Linux).

Здесь вы можете использовать GNU xargsвместо parallelупрощенной обработки, приближенной к ожидаемой:

printf '1\n2\n' | xargs -rn1 -P4 bash -c 'echo ":$1"' ''

Смотрите также обсуждение по адресу https://lists.gnu.org/archive/html/bug-parallel/2015-05/msg00005.html.

Обратите внимание, что bash -c 'echo foo' '' fooвы создаете $0пустую строку для этого встроенного скрипта. Я бы избегал этого, поскольку это $0также используется в сообщениях об ошибках. Для сравнения:

$ bash -c 'echo x > "$1"' '' /
: /: Is a directory

с.

$ bash -c 'echo x > "$1"' bash /
bash: /: Is a directory

Также обратите внимание, что оставление переменных без кавычек имеет очень особое значение bashи, echoкак правило, не может использоваться для произвольных данных.

Стефан Шазелас
источник
4
Mon Dieu! Это лучший ответ, чем мог бы написать автор GNU Parallel.
Оле Танге