Как я могу ссылаться на динамически изменяющийся индекс массива внутри параллельной команды в bash

#bash #parallel-processing

#bash #параллельная обработка

Вопрос:

Я пишу параллельную команду в bash, и мне нужно указать элемент массива, индекс которого изменяется в зависимости от номера задания параллельного выполнения задания, в качестве аргумента.

Я пытался использовать переменную $PARALLEL_SEQ, но я не могу заставить синтаксис работать.

 #!/usr/bin/env bash

test_array=(apple orange lemon mango banana)
seq 5 | parallel echo ${test_array[$PARALLEL_SEQ]}
  

Я ожидаю, что второй аргумент после parallel будет вычислен со строкой в результате (например, ‘orange’ для второго параллельного выполнения).
Я хочу, чтобы мой код печатался:

 apple
orange
lemon
mango
banana
  

и не:

 apple 1
apple 2
apple 3
apple 4
apple 5
  

Ответ №1:

из вашей команды PARALLEL_SEQ расширяется th shell перед вызовом parallel.

из документации

Однако, если вы хотите использовать переменную оболочки, вам нужно заключить знак $ в кавычки. Вот пример использования $PARALLEL_SEQ . Эта переменная устанавливается самой GNU parallel, поэтому вычисление $ должно выполняться вспомогательной оболочкой, запущенной GNU parallel:

 seq 10 | parallel -N2 echo seq:$PARALLEL_SEQ arg1:{1} arg2:{2}
  

После комментария я смог найти cygwin с parallel и мог протестировать следующие команды, которые сработали:

 foo(){ test_array=(apple orange lemon mango banana);}
export -f foo
seq 5 | parallel 'foo amp;amp; echo "${test_array[PARALLEL_SEQ-1]}" amp;amp; : '
  

обходной путь из-за невозможности экспорта массивов через среду

: в конце находится команда no-op, поэтому последний аргумент, переданный parallel, не принимается в качестве аргумента для команды echo.

Комментарии:

1. Я не вижу, как это может решить мою проблему с выводом правильного значения из массива. Не могли бы вы уточнить, как я могу добиться желаемого результата? Обратите внимание, что порядок печатных элементов может отличаться, поскольку команды выполняются параллельно. Заранее спасибо.

2. я не смог протестировать, потому что у меня нет среды с установленным parallel, но вам, возможно, придется экспортировать массив (или, может быть, просто использовать его напрямую, потому что подоболочка может видеть неэкспортированные переменные), но вам нужно выполнить escape $ , чтобы предотвратить расширение текущей оболочки до того, как parallel сможет их увидеть. Может быть, просто используя одинарные кавычки echo '${test_array[$PARALLEL_SEQ]}'

Ответ №2:

env_parallel сделано для вас:

 # Ignore all variables set now
env_parallel --start
# Introduce a new variable
test_array=(apple orange lemon mango banana)
# Copy that variable to the environment of the command
seq 5 | env_parallel echo '${test_array[{= $_=seq() -1 =}]}'
  

Он работает даже на удаленных системах:

 # Copy that variable to the environment of the command on the remote server
seq 5 | env_parallel -S server echo '${test_array[{= $_=seq() -1 =}]}'
  

Однако для этого вам понадобится довольно новая версия GNU Parallel.