パラレル変数宣言sh -c…

パラレル変数宣言sh -c…

find私はwithの出力を処理しようとしましたがparallel、これは順番にシェルを呼び出します(一部のテキスト置換が必要です)。私は自分で説明できない奇妙な行動を観察しました。

各ディレクトリには複数のファイルがありますfile1.xtcfile2.xtcそのいくつかはfile1.part0002.xtc。渡されたファイルにfindその名前がある場合は、結果コマンドが次のように見えるように*.part000x.*そのビットを削除する必要があります。*.part000x.*

command -f file1.part0001.xtc -s file1.tpr 

findandを使用してparallelこの効果を得ましたが、parallel代替項目(特にビット{.})が十分ではありませんでした(.xtc拡張子を削除して.part0001そのままにしました)。したがって、出力を確認するために使用したコマンドは次のようになります。

find 1st 2nd 3rd -name '*.xtc' -print0 | parallel -0 sh -c 'name=""; name="{.}"; echo {.} ${name%.*}.tpr'

上記のコマンドを使用して最初に宣言し、空のname文字列(またはその問題の他の項目)を割り当てると、結果は次のようになります。

file1.part0001 file1.tpr

必要に応じて(これは私のコマンドが使用する必要がある名前です)が、これを実行すると

find 1st 2nd 3rd -name '*.xtc' -print0 | parallel -0 sh -c 'name="{.}"; echo {.} ${name%.*}.tpr'

結果:

file1.part0001 .tpr

$nameまたは存在しないかのように動作します。

だから私の質問は次のようになります

- このような行動をする理由は何ですか?

- この問題を処理するための好ましい方法は何ですか?

ここで最初の質問はより重要です。上記で使用した方法は見栄えが良くありませんが、うまくいく解決策だからです。このようにテキストを置き換える必要があったのは今回が初めてではなく、この振る舞いはまだ私を恥ずかしくさせます。

出力sh --version

GNU bash, version 3.2.48(1)-release (x86_64-apple-darwin11)

bash上記のコマンドで代わりにインストールして使用した最新バージョンの出力sh(同じ効果を得るために)(/usr/local/bin/bash --version

GNU bash, version 4.2.0(1)-release (i386-apple-darwin11.4.2)

答え1

あなたの問題はbashとは関係ありません。実際、parallelrunと言った後はshそれを使用しないかもしれませんbash

問題は、ドキュメントが示すように、パラレルがxargsを実際に置き換えないことです。代わりに、引数を単一の文字列(間にスペースを含む)として累積してから、一連のコマンドとして解釈します。したがって、あなたの場合には、以下があります。

sh -c 'name="{.}"; echo {.} ${name%.*}.tpr'

これは次のように解釈されます。

sh -c 'name="{.}";
echo {.} ${name.*}.tpr

これは2つの別々のコマンドで、最初のコマンドsh -cはサブシェル()で実行されるため、$name2番目のコマンドには設定されません。

これで、文字列の先頭に何でも追加できますtrue。たとえば、次のようになります。

sh -c 'true; name="{.}"; echo {.} ${name%.*}.tpr'

これは次のように解釈されます。

sh -c 'true'
name="{.}"
echo {.} ${name%.*}.tpr'

この場合、呼び出しはsh本質的にワンタイムであり、namesetによって維持される環境で設定され、parallel最後にsetechoとして呼び出されますname

したがって、最も簡単な解決策は不要な呼び出しを削除するようですsh

find 1st 2nd 3rd -name '*.xtc' -print0 |
parallel -0 'name={.}; echo {.} "${name%.*}.tpr"'

メモ:@StephaneChazelasが提供したヒントに従って、二重引用符を削除して{.}周囲に追加しました${name%.*}.ptr。並列参照は自己置換を使用するため、奇妙な方法で明示的な参照を妨げます。ただし、代替アイテムがトークン化される可能性がある場合、追加する必要があるシェル代替アイテムには引用符を追加しません。

何らかの理由でサブシェル(または特定のサブシェル)を本当に使用したい場合は、別のオプションは次のものを使用することです-q

find 1st 2nd 3rd -name '*.xtc' -print0 |
parallel -0 -q sh -c 'name="{.}"; echo "{.}" "${name%.*}.tpr"'

メモ:上記のように提案を調整しました。この場合、-q代替項目への参照は明示的に禁止されるため、明示的に参照する必要があります。ただし、これはシェル引用符ほど正確ではないテキスト引用符です。代替引用符に二重引用符文字が含まれている場合、その文字はエスケープされず、明示的な引用符がオフになり、コマンドラインが中断され、効果的に挿入されます。コマンドインジェクションの脆弱性($`または\文字を含むファイル名)。このため、何よりも-qこのオプションはお勧めできません。

関連情報