2つの(パイプライン)シェルコマンドをシェル関数の引数として渡します。

2つの(パイプライン)シェルコマンドをシェル関数の引数として渡します。

次のシェル関数を定義しました。

success() {
  printf "[\033[32mSUCCESS\033[0m]\n"
}

failure() {
  printf "[\033[31mFAILURE\033[0m]\n"
}

try() {
  result=$($* 2>&1)
  if [ $? -ne 0 ]; then
    failure
    echo $result
    exit 1
  fi
  success
}

これにより、すべてのコマンドを自動的に実行したり、すべての出力をキャプチャしたり、表示したり、SUCCESSメッセージFAILUREを表示したりできます。コマンド出力は、コマンドが失敗した場合にのみデバッグ目的で表示されます。

try rm -r $tmp

しかし、私はそれが単一のコマンドに制限され、他のコマンドにパイプされたコマンドに対して悲惨に失敗することに気づきました|

try git archive --format=tar HEAD | tar xf - -C $tmp

tryコマンドに対してのみ実行されるので、のgit出力はの出力ではなくtryパイプされます。targit

git ... | tar ...両方のコマンドを単一の引数として渡すことはできますか?try、両方の出力をキャプチャし、両方が返されることをgit確認してください。tar0

私の目標を達成するために他の考慮事項はありますか?

ベストアンサー1

git … | tar …パイプ(2つの個別のコマンドではなく2つのサブコマンドを含む単一のコマンド)を関数に直接引数として渡すには、コマンドを含む文字列を作成し、関数に組み込まれた関数evalを使用する必要があります。この文字列をシェルコマンドとして実行します。

正しい引用に注意してください。引数の場合は、インクルードスクリプトと同じ変数を使用してミニシェルスクリプトである文字列を作成します。特に、変数にファイル名が含まれている場合(tmpここでのように)、変数値ではなく変数拡張を渡す必要があります。ファイル名はシェルの断片ではなく、'…"$tmp"…'代わりに拡張が必要な​​ためです"…$tmp…"。評価するときは、eval拡張文字列ではなく正確な文字列を渡す必要があります。特に、$*ほとんど常に間違った内容を読みます。スペースやその他の特殊文字が原因でシェルスクリプトが停止するのはなぜですか?

try () {
  result=$(eval "$1" 2>&1)
  if [ $? -ne 0 ]; then
    failure
    echo $result
    exit 1
  fi
  success
}
try 'git archive --format=tar HEAD | tar xf - -C "$tmp"'

別のアプローチは、複合コマンドを関数に入れることです。もう一度正確に引用してください。"$@"関数のパラメーターを単純なコマンド(別名、関数、パラメーター付きの組み込みまたは外部コマンド)として評価するために使用されます。

try () {
  result=$(eval "$1" 2>&1)
  if [ $? -ne 0 ]; then
    failure
    echo $result
    exit 1
  fi
  success
}
archive_to_directory () {
  git archive --format=tar HEAD | tar xf - -C "$1"'
}
try archive_to_directory "$tmp"

パイプの状態は右側の状態で、左側の状態は無視されます。 bashでは(shではない)、次のようにパイプライン内のすべてのコマンドステータスにアクセスできます。PIPESTATUS変える

try () {
  result=$(eval "$1" 2>&1)
  if [ $? -ne 0 ]; then
    failure
    echo $result
    exit 1
  fi
  success
}
archive_to_directory () {
  git archive --format=tar HEAD | tar xf - -C "$1"'
  [[ -n ${PIPESTATUS[*]//[0 ]/} ]]
}
try archive_to_directory "$tmp"

おすすめ記事