Функции GNU Parallel и Bash: как запустить простой пример из руководства

Я пытаюсь изучить GNU Parallel, потому что у меня есть случай, когда я могу легко распараллелить функцию bash. Поэтому, пытаясь учиться, я обратился к Руководству по GNU Parallel, где есть пример... но я даже не могу заставить его работать! Для остроумия:

(232) $ bash --version
GNU bash, version 4.1.2(1)-release (x86_64-redhat-linux-gnu)
Copyright (C) 2009 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>

This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
(233) $ cat tpar.bash
#!/bin/bash

echo 'which parallel'
doit() {
  echo Doing it for $1
  sleep 2
  echo Done with $1
}
export -f doit
parallel doit ::: 1 2 3
doubleit() {
  echo Doing it for $1 $2
  sleep 2
  echo Done with $1 $2
}
export -f doubleit
parallel doubleit ::: 1 2 3 ::: a b

(234) $ bash tpar.bash
/home/mathomp4/bin/parallel
doit: Command not found.
doit: Command not found.
doit: Command not found.
doubleit: Command not found.
doubleit: Command not found.
doubleit: Command not found.
doubleit: Command not found.
doubleit: Command not found.
doubleit: Command not found.

Как видите, я даже не могу запустить простой пример. Таким образом, я, вероятно, делаю что-то удивительно глупое и простое... но я в растерянности.

ETA: как предложено комментаторами (chmod +x, установите -vx):

(27) $ ./tpar.bash

echo 'which parallel'
which parallel
++ which parallel
+ echo /home/mathomp4/bin/parallel
/home/mathomp4/bin/parallel

doit() {
  echo Doing it for $1
  sleep 2
  echo Done with $1
}
export -f doit
+ export -f doit
parallel doit ::: 1 2 3
+ parallel doit ::: 1 2 3
doit: Command not found.
doit: Command not found.
doit: Command not found.
doubleit() {
  echo Doing it for $1 $2
  sleep 2
  echo Done with $1 $2
}
export -f doubleit
+ export -f doubleit
parallel doubleit ::: 1 2 3 ::: a b
+ parallel doubleit ::: 1 2 3 ::: a b
doubleit: Command not found.
doubleit: Command not found.
doubleit: Command not found.
doubleit: Command not found.
doubleit: Command not found.
doubleit: Command not found.

ETA2: обратите внимание, я могу, в сценарии, просто вызвать 'doit 1', скажем, и он сделает это. Таким образом, функция действительна, она просто... не экспортируется?

Ответ 1

Вы не можете вызвать функцию оболочки из-за оболочки, где она была определена. Функция оболочки - это концепция внутри оболочки. Сама команда parallel не имеет доступа к ней.

Вызов export -f doit в bash экспортирует функцию через среду, чтобы ее подхватили дочерние процессы. Но только bash понимает функции bash. A (grand) * child bash процесс может вызывать его, но не другие программы, например, не другие оболочки.

Идя по сообщению "Команда не найдена", кажется, что ваша предпочтительная оболочка - это (t) csh. Вы должны сказать parallel для вызова bash. parallel вызывает оболочку, обозначенную переменной окружения SHELL¹, поэтому установите для нее значение bash.

export SHELL=$(type -p bash)
doit () { … }
export -f doit
parallel doit ::: 1 2 3

Если вы хотите установить SHELL для выполнения команды parallel, а не для остальной части script:

doit () { … }
export -f doit
SHELL=$(type -p bash) parallel doit ::: 1 2 3

Я не уверен, как работать с удаленными заданиями, вам может потребоваться передать --env=SHELL в дополнение к --env=doit (примечание что это предполагает, что путь к bash везде везде).

И да, эту странность следует упомянуть более подробно в руководстве. В описании описания command есть краткое примечание, но оно не очень явное (должно объясняться, что слова command объединяются с пространством в качестве разделителя и затем передаются в $SHELL -c), а SHELL даже не упоминается в переменных окружения, (Я призываю вас сообщить об этом как об ошибке, я не делаю этого, потому что я почти никогда не использую эту программу.)

¹ , который является плохим дизайном, поскольку SHELL должен указывать предпочтение пользовательского интерфейса для оболочки командной строки, а не изменять поведение программ.

Ответ 2

Начиная с версии 20160722 вы можете вместо этого использовать env_parallel:

doit() { echo "[email protected]"; }
echo world | env_parallel doit Hello

Вам просто нужно активировать env_parallel, добавив его в .bashrc. Вы можете добавить его в .bashrc, запустив один раз:

env_parallel --install