echo コマンドの実行トレースを抑制しますか?

echo コマンドの実行トレースを抑制しますか?

私は Jenkins からシェル スクリプトを実行しています。これにより、シェル スクリプトが shebang オプションで起動されます#!/bin/sh -ex

によると初心者向けの Bash Shebang ですか?-x、 「シェルに実行トレースを印刷させる」 これは、エコーを除くほとんどの目的には最適です。

echo "Message"

出力を生成する

+ echo "Message"
Message

これは少し冗長で、少し奇妙に見えます。-x有効のままにして、出力のみにする方法はありますか?

Message

上記の 2 行の代わりに、たとえば echo コマンドの前に特殊なコマンド文字を付けたり、出力をリダイレクトしたりすることはできますか?

答え1

ワニに首までつかっていると、沼地を干拓することが目的だったことを忘れてしまいがちです。—                   よく言われていること

質問はechoしかし、これまでの回答の大部分は、set +xコマンドをこっそりと挿入する方法に焦点を当てています。もっとシンプルで直接的な解決策があります。

{ echo "Message"; } 2> /dev/null

{ …; } 2> /dev/null (以前の回答を見ていなければ、そのことについては考えなかったかもしれないと認めます。)

これは多少面倒ですが、連続したコマンドのブロックがある場合はecho、それぞれを個別に実行する必要はありません。

{
  echo "The quick brown fox"
  echo "jumps over the lazy dog."
} 2> /dev/null

改行がある場合はセミコロンは不要であることに注意してください。

入力の負担を軽減するには、ケノーブのアイデア/dev/null非標準のファイル記述子 (例: 3) で永続的に 開き、2>&3代わりに常にと言うことです2> /dev/null


この記事を書いている時点での最初の4つの答えは、特別なこと(そしてほとんどの場合面倒なこと)をする必要がある。 やる時はやるecho。本当にやりたいなら全て echo実行トレースを抑制するコマンド (なぜそうしないのでしょうか?) を使用すると、多くのコードを変更することなく、グローバルに実行トレースを抑制することができます。まず、エイリアスはトレースされないことに気付きました。

$ myfunc()
> {
>     date
> }
$ alias myalias="date"
$ set -x
$ date
+ date
Mon, Oct 31, 2016  0:00:00 AM           # Happy Halloween!
$ myfunc
+ myfunc                                # Note that function call is traced.
+ date
Mon, Oct 31, 2016  0:00:01 AM
$ myalias
+ date                                  # Note that it doesn’t say  + myalias
Mon, Oct 31, 2016  0:00:02 AM

(次のスクリプト スニペットは#!/bin/sh、 が bash へのリンクであっても、シェバンが であれば機能することに注意してください/bin/sh。ただし、 が の場合は#!/bin/bash、スクリプトでエイリアスを機能させるには、 コマンドを追加する必要がありますshopt -s expand_aliases。)

それで、私の最初のトリックは:

alias echo='{ set +x; } 2> /dev/null; builtin echo'

ここで、 と言うとecho "Message"、トレースされないエイリアスを呼び出します。エイリアスはトレースオプションをオフにし、setコマンドからのトレースメッセージを抑制します(最初に紹介したテクニックを使用)。user5071535の回答)を実行し、実際のechoコマンドを実行します。これにより、コードを編集することなく、user5071535の回答と同様の効果を得ることができます。 echoコマンド。ただし、これではトレースモードはオフのままです。set -xエイリアスでは文字列を単語に置き換えることしかできないため、エイリアスに a を入れることはできません(少なくとも簡単にはできません)。エイリアス文字列のどの部分もコマンドに挿入することはできません。 引数(例:"Message")。例えば、スクリプトに

date
echo "The quick brown fox"
echo "jumps over the lazy dog."
date

出力は次のようになる

+ date
Mon, Oct 31, 2016  0:00:03 AM
The quick brown fox
jumps over the lazy dog.
Mon, Oct 31, 2016  0:00:04 AM           # Note that it doesn’t say  + date

そのため、メッセージを表示した後はトレースオプションをオンに戻す必要がありますが、これは毎回1回だけです。ブロック連続したechoコマンド:

date
echo "The quick brown fox"
echo "jumps over the lazy dog."
set -x
date


それはいいだろうset -xの後に を自動で実行できればecho、もう少し工夫すれば可能です。しかし、その前に、次の点を考慮してください。OP は、シェバンを使用するスクリプトから始めています#!/bin/sh -ex。暗黙的に、ユーザーは をxシェバンから削除して、実行トレースなしで正常に動作するスクリプトを作成できます。その特性を保持するソリューションを開発できればよいでしょう。ここでの最初のいくつかの回答は、トレースがすでにechoオンになっているかどうかに関係なく、ステートメントの後に無条件にトレースを「オンに戻す」ため、その特性を満たしていません。  この答えこの問題を認識していないのは明らかだ。置き換える echoトレース出力で出力されます。したがって、トレースをオフにするとすべてのメッセージが消えます。次に、ステートメントの後にトレースをオンに戻すソリューションを紹介しますecho条件付きで— すでにオンになっている場合のみです。これを、トレースを「戻す」ことを無条件にオンにするソリューションにダウングレードするのは簡単なので、演習として残しておきます。

alias echo='{ save_flags="$-"; set +x;} 2> /dev/null; echo_and_restore'
echo_and_restore() {
        builtin echo "$*"
        case "$save_flags" in
         (*x*)  set -x
        esac
}

$-はオプション リストです。これは、設定されているすべてのオプションに対応する文字の連結です。たとえば、およびオプションが設定されている場合exは、$-およびを含む文字の羅列になりますex私の新しいエイリアス (上記) は、トレースをオフにする前に の値を保存します$-。次に、トレースをオフにして、シェル関数に制御を渡します。その関数は実際の を実行しecho 、エイリアスが呼び出されたときにオプションがオンになっていたかどうかを確認しますx。オプションがオンになっていた場合、関数はそれをオンに戻します。オプションがオフになっていた場合、関数はそれをオフのままにします。

上記の 7 行 ( を含める場合は 8 行shopt) をスクリプトの先頭に挿入し、残りはそのままにしておくことができます。

これにより、

  1. 次のいずれかのシェバン行を使用します。
    #!/bin/sh -ex
    #!/bin/sh -e
    #!/bin/sh –x
    あるいは単に
    #!/bin/sh
    期待通りに動作するはずです。
  2. 次のようなコードを持つ
    (シェバン)
    コマンド1
    コマンド2
    コマンド3
    -x を設定する
    コマンド4
    コマンド5
    コマンド6
    +x を設定
    コマンド7
    コマンド8
    コマンド9
    そして
    • コマンド 4、5、6 はトレースされます。ただし、そのうちの 1 つが であるecho場合は、実行されますがトレースされません。(ただし、コマンド 5 が の場合でもecho、コマンド 6 はトレースされます。)
    • コマンド 7、8、9 はトレースされません。コマンド 8 が であってもecho、コマンド 9 はトレースされません。
    • コマンド 1、2、3 は、シェバンに が含まれているかどうかに応じて、トレースされるか (コマンド 4、5、6 のように)、トレースされないか (コマンド 7、8、9 のように) が決まりますx

builtinPS 私のシステムでは、中間の回答 ( のエイリアスにすぎないもの) のキーワードを省略できることを発見しましたecho。これは驚くことではありません。bash(1) は、エイリアスの展開中に、… と述べています。

… エイリアスと同じ単語が展開された場合、2度目は展開されません。つまり、lsls -Fたとえば、bash は置換テキストを再帰的に展開しようとしません。

驚くことではありませんが、最後の答え ( を含むものecho_and_restore) は、builtinキーワードが省略されている場合は失敗します1builtin 。しかし、奇妙なことに、 を削除して順序を入れ替えると機能します。

echo_and_restore() {
        echo "$*"
        case "$save_flags" in
         (*x*)  set -x
        esac
}
alias echo='{ save_flags="$-"; set +x;} 2> /dev/null; echo_and_restore'

__________
1 未定義の動作を引き起こすようです。

  • 無限ループ(おそらく無制限の再帰によるもの)、
  • エラー/dev/null: Bad addressメッセージ、および
  • コアダンプ。

答え2

私は部分的な解決策を見つけましたインフォメーションIT:

#!/bin/bash -ex
set +x; 
echo "shell tracing is disabled here"; set -x;
echo "but is enabled here"

出力

set +x; 
shell tracing is disabled here 
+ echo "but is enabled here"
but is enabled here

残念ながら、まだ反響は残っていますset +xが、少なくともその後は静かになりました。したがって、少なくとも問題は部分的に解決されました。

しかし、これを行うにはもっと良い方法があるのでしょうか? :)

答え3

この方法は、出力を取り除くことで独自のソリューションを改善しますset +x

#!/bin/bash -ex
{ set +x; } 2>/dev/null
echo "shell tracing is disabled here"; set -x;
echo "but is enabled here"

答え4

set +x括弧内に入れると、ローカル スコープにのみ適用されます。

例えば:

#!/bin/bash -x
exec 3<> /dev/null
(echo foo1 $(set +x)) 2>&3
($(set +x) echo foo2) 2>&3
( set +x; echo foo3 ) 2>&3
true

出力は次のようになります:

$ ./foo.sh 
+ exec
foo1
foo2
foo3
+ true

関連情報