xargsを使用したシェル関数の呼び出し


168

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をどのように使用できるか、またはその他の解決策に関するアイデアがあれば歓迎します。


2
危険、user1148366、危険!並列プログラミングにbashを使用しないでください。非常に多くの問題が発生します。C / C ++とpthreads、Javaスレッド、または何をしているのかについて長く考えにくいものを使用します。並列プログラミングは正しく理解するために多くのことを考えているためです。
デビッドサウザー

27
@DavidSoutherこれらすべての画像ファイルをpngに変換するなど、タスクが独立している場合は、心配しないでください。同期(すべてが完了するのを待つ)と通信が乱れるときです。
ctrl-alt-delor 14

@DavidSouther-私は長い間Java開発者であり、最近グルーヴィーな仕事をしています。そして私は人々に言い続けます:友達は友達にbashスクリプトを書かせません。(sad face :()私はbashで並列処理に従事しています。groovy/ javaですぐに実行できました。Bad!
Christian Bongiorno

回答:


172

関数のエクスポートはそれを行うべきです(テストされていません):

export -f echo_var
seq -f "n%04g" 1 100 | xargs -n 1 -P 10 -I {} bash -c 'echo_var "$@"' _ {}

printf外部の代わりに組み込みを使用することができますseq

printf "n%04g\n" {1..100} | xargs -n 1 -P 10 -I {} bash -c 'echo_var "$@"' _ {}

また、そのようなものを使用するreturn 0exit 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 "$@"' _ {}
$(date)

これは、注入を回避するためにパラメータ化された SQL クエリを使用することに相当します

私が使用しているdateコマンド置換またはエスケープ引用符ここの代わりにrm、それは非破壊ですので、サーシャさんのコメントで使用されるコマンド。


14
もう少し議論:xargsは、指定されたプロセスの完全に新しいインスタンスを実行します。この場合echo_varは、PATHにプロセス(プログラム)ではなく、このスクリプトの関数であるnameを指定します。Dennisのソリューションが行うことは、子bashプロセスが使用する関数をエクスポートし、サブプロセスにフォークしてそこで実行することです。
デビッドサウザー

7
_およびの意味は何\
ですか

9
@Hashbrown:アンダースコアは、( _)のためのプレースホルダを提供argv[0]$0)とほとんど何が使用することができます。バックスラッシュセミコロン(\;)を追加したのは、で-exec句を終了するために使用したfindためですが、ここではそれがなくても機能します。実際、関数が$@代わりに使用する場合は$1、セミコロンがパラメーターとして認識されるため、省略する必要があります。
追って通知があるまで一時停止。

4
xargsの-i引数は非推奨になりました。代わりに-I(大文字のi)を使用してください。
Nicolai S

11
これは、bashのコマンド文字列にxargsからの引数を含めることで簡略化できbash -c 'echo_var "{}"'ます。したがって、最後に_ {}は必要ありません。
恐怖症

16

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 {} 

どこでosxを購入できますか?
Nick

nvmそれはzshでsetoptです
Nick 15

これを下に取得eerror Ole sh: parallel_bash_environment: line 67: unexpected EOF while looking for matching '' sh:parallel_bash_environment:line 79:syntax error:エラーend of file sh:error importing function definition for parallel_bash_environment' /usr/local/bin/bash: parallel_bash_environment: line 67: unexpected EOF while looking for matching '' / usr / local / bin / bash:parallel_bash_environment:line 79:syntax error:予期しない終わりファイル/ usr / local / bin / bash: `...のインポート関数定義エラー
Nick

あなたはshellaftershockedされました:ShellshockはGNU Parallelに直接影響しませんでした。ただし、shellshockの解決策は次のとおりです。--envとenv_parallelトリックを完全に壊しました。Gitのバージョンで修正されると考えられている:git.savannah.gnu.org/cgit/parallel.git/snapshot/...
オーレ丹下

1
それが作られたので、私はこの答えのように、私は、パラレルツールを発見
JR Utily

10

このようなものも機能するはずです:

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

1

多分これは悪い習慣ですが、.bashrcまたは他のスクリプトで関数を定義している場合は、ファイルまたは少なくとも関数定義を次の設定でラップできます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
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.