パイプを通してTピースにエクスポートすると、条件が壊れます。

パイプを通してTピースにエクスポートすると、条件が壊れます。

サーバーにカスタムファイアウォールルールがあるかどうかをテストしようとしています。 awkを使用してiptables出力を処理し、適切な終了コードを返すことでこれを行います。これは期待どおりに機能し、正しい結果を印刷します。ただし、ティーにパイプで接続すると、条件は機能しなくなり、毎回結果が印刷されます。

# The broken code
ssh server1 'sudo iptables -L | awk "(!/ACCEPT/ && !/^target/ && !/^$/) {rules=1 ;} (rules==1) {exit 1}" && printf "%s\n" "string1" "string2" | sudo tee -a /path/to/file'
# The same code without `| sudo tee -a /path/to/file` works as intended
ssh server1 'sudo iptables -L | awk "(!/ACCEPT/ && !/^target/ && !/^$/) {rules=1 ;} (rules==1) {exit 1}" && printf "%s\n" "string1" "string2"'

私は何を見逃していますか?私はRHEL8でGNU coretils 8.30とGNU bashバージョン4.4.20(1)を使用しています。私はawkのドアが短くなる可能性があることを知っていましたが、それはポイントではありません。 :D

ベストアンサー1

あなたの苦情は主にパイプから返された状態に関するものですiptables ... | awk ... && printf ... | tee ... 。飼育剤文書 その価値が何であるかを説明してください。

パイプライン障害オプションが有効になっていない場合、パイプラインの戻り状態は最後のコマンドの終了状態です。 Pipefailが有効な場合、パイプラインの戻り状態は、ゼロ以外の状態で終了した最後の(最も右側の)コマンドの値、またはすべてのコマンドが正常に終了した場合は0です。

実行を検討してください

set -o pipefail

パイプラインの結果前。

あるいは、より簡単な場合は、... | (cmd ... || true) | ...イディオムを使用して各ステップを返すことができます。0例外が検出されたら、それ以降のパイプライン段階でgrepそれを処理できるように固有のメッセージをエクスポートします。

bashにawkの単純処理とprintfの単純処理を条件付きで調整させる設計決定は、当時は合理的だったかもしれませんが、今はこれが生産性を低下させることがわかります。このロジックを単純なawkスクリプトに統合することを検討してください。


短いパイプを使用する方が便利かもしれません。

ssh server1 ... | awk ...  > server1.txt
# awk exit status is now available in $? so you can conditionally run printf

cat server1.txt  >> /path/to/file

もともとの質問では、/path/to/file はサーバーパス名であり、私たちは少し複雑な一行のリモートパイプラインを実行していました。iptables -L SSH接続を介して生の出力を返し、ローカルパイプラインを実行する方が便利です。ローカル結果ファイルを作成したら、いつでも次のように保存できます。

cat results.txt | ssh server1 'cat >> /path/to/file'

おすすめ記事