次のシェル関数を定義しました。
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
パイプされます。tar
git
git ... | tar ...
両方のコマンドを単一の引数として渡すことはできますか?try
、両方の出力をキャプチャし、両方が返されることをgit
確認してください。tar
0
私の目標を達成するために他の考慮事項はありますか?
答え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"
答え2
コマンドラインに引用符を追加する必要があります。これは避けられません。
try "git archive --format=tar HEAD | tar xf - -C $tmp"
その後、関数では、シェルメタ文字(たとえば|
)は変数に格納されるときに特別ではないため、次のものが必要です。eval
try() {
if result=$(eval "$*" 2>&1); then
success
else
failure
echo $result
exit 1
fi
}
まだこの部分が正しく理解されていないという感じがします。誰かが私を修正できることを願っています。