Вызов функций оболочки с помощью xargs

Я пытаюсь использовать xargs для вызова более сложной функции параллельно.

#!/bin/bash
echo_var(){
    echo $1
    return 0
}
seq -f "n%04g" 1 100 |xargs -n 1 -P 10 -i echo_var {} 
exit 0

Это возвращает ошибку

xargs: echo_var: No such file or directory

Любые идеи о том, как я могу использовать xargs для этого, или любое другое решение (ы), приветствуются.

Ответ 1

Экспорт функции должен сделать это (не проверено):

export -f echo_var
seq -f "n%04g" 1 100 | xargs -n 1 -P 10 -I {} bash -c 'echo_var "[email protected]"' _ {}

Вы можете использовать встроенный printf вместо внешнего seq:

printf "n%04g\n" {1..100} | xargs -n 1 -P 10 -I {} bash -c 'echo_var "[email protected]"' _ {}

Кроме того, использование return 0 и exit 0 подобным образом маскирует любое значение ошибки, которое может быть вызвано предшествующей ему командой. Кроме того, если ошибки нет, она используется по умолчанию и, следовательно, несколько избыточна.

@phobic упоминает, что команду Bash можно упростить до

bash -c 'echo_var "{}"'

перемещая {} прямо внутри него. Но он уязвим для внедрения команд, как отмечает @Sasha.

Вот пример, почему вы не должны использовать встроенный формат:

$ echo '$(date)' | xargs -I {} bash -c 'echo_var "{}"'
Sun Aug 18 11:56:45 CDT 2019

Еще один пример того, почему нет:

echo '\"; date\"' | xargs -I {} bash -c 'echo_var "{}"'

Это то, что выводится в безопасном формате:

$ echo '$(date)' | xargs -I {} bash -c 'echo_var "[email protected]"' _ {}
$(date)

Это сравнимо с использованием параметризованных SQL запросов, чтобы избежать внедрения.

Я использую date в подстановке команд или в экранированных кавычках здесь вместо команды rm, используемой в комментарии Саши, так как она неразрушающая.

Ответ 2

Использование GNU Parallel выглядит так:

#!/bin/bash
echo_var(){
    echo $1
    return 0
}
export -f echo_var
seq -f "n%04g" 1 100 | parallel -P 10 echo_var {} 
exit 0

Если вы используете версию 20170822, вам даже не нужно export -f, пока вы это запустили:

. `which env_parallel.bash`
seq -f "n%04g" 1 100 | env_parallel -P 10 echo_var {} 

Ответ 3

Что-то вроде этого тоже должно работать:

function testing() { sleep $1 ; }
echo {1..10} | xargs -n 1 | xargs [email protected] -P4 bash -c "$(declare -f testing) ; testing @ ; echo @ "

Ответ 4

Возможно, это плохая практика, но если вы определяете функции в .bashrc или другом script, вы можете обернуть файл или, по крайней мере, определения функций с помощью параметра allexport:

set -o allexport

function funcy_town {
  echo 'this is a function'
}
function func_rock {
  echo 'this is a function, but different'
}
function cyber_func {
  echo 'this function does important things'
}
function the_man_from_funcle {
  echo 'not gonna lie'
}
function funcle_wiggly {
  echo 'at this point I\'m doing it for the funny names'
}
function extreme_function {
  echo 'goodbye'
}

set +o allexport