Bash:抑制後にstderrを再度開く

Bash:抑制後にstderrを再度開く

gitを自動的にインストール/削除するためにこのスクリプトを作成しました。 gitがインストールされているかどうかをテストする関数は、コマンドを使用してgit --version戻りコードをテストします。

私はクールなカスタム出力を作成しようとしているので、通常どおりstderr出力が好きではありません。この機能に対してのみstderrを抑制する方法を見つけましたが、再度有効にすることはできません。

この関数を呼び出すと、readプロンプトは消えます。

function CheckGit() {
    exec 3>&2           # link file desc 3 w/ stderr
    exec 2> /dev/null

    SILENT_MODE=$1

    if [[ ! $(git --version) ]]; then
        if [ SILENT_MODE ]; then
            printf "${LT_RED} GIT IS NOT INSTALLED.\n"
        fi
        continue;
    else
        if [ SILENT_MODE ]; then
            printf "${LT_BLUE} GIT IS CURRENTLY INSTALLED.\n"
        fi
        continue;
    fi
    GIT_INSTALLED=$?
    #turn back on the stderr notifications
    exec 2>&3 3>&-      # Restore stdout and close file descriptor #3
}

while true; do
    printf "${LT_BLUE} Menu\n"
    printf " ***********************************************\n"
    printf "${LT_GREEN} a) Check git.\n"
    printf "${LT_GREEN} b) (More to be added)\n"
    printf "${LT_GREEN} c) ...\n"
    printf "${LT_GREEN} d) ...\n"
    printf "${LT_GREEN} h) ...\n"
    printf "${LT_RED} x) Exit.\n"
    printf "\n${NC}"
    read -p "Please make a selection: " eotuyx
    case $eotuyx in
        [Aa]* ) CheckGit true; continue;;
        [Bb]* ) ...; continue;;
        [Cc]* ) ...; continue;;
        [Dd]* ) ...; continue;;
        [Hh]* ) ...; continue;;
        [XxQq]* ) break;;
        * ) -e "\n${NC}" + "Please answer with a, b, c, d, x(or q).";;
    esac
done

答え1

与えられたアドバイスを繰り返すコメントから:

  1. continue関数から文を削除しますCheckGit
    • それらは必要ありません。
    • そして - あなたはそれを認識できないかもしれません - これは(関数から)メインループにすぐに返されるだけでなく、メインループのwhile true上部にあるステートメントにすぐに返されます。したがって、次のようにトーマスは指摘した、あなたのexec 2>&3 3>&-文が実行されていません。

一般:

  1. if [ SILENT_MODE ]いつも正しいからMosviが指摘した。これは、文字列がSILENT_MODE空でないかどうかをテストするだけです。あなたがしたいようですif [ "$SILENT_MODE" ]
  2. しかし、冗談かもしれません。 is が trueif [ "$SILENT_MODE" ]の場合でも実行する操作は、文字列が null でないかどうかをテストするだけなので、呼び出すと情報が表示されます。$SILENT_MODEfalseCheckGit false
  3. そして、自分をだましていなくても、来週このスクリプトを維持する必要がある人をだますこともできます。はい、その人はまさにあなたかもしれません。あなたの明白なロジックは、「自動モードの場合は追加情報を報告してください」です。これは論理的に反対です。if [ "$SILENT_MODE" = false ]変数を話すか呼び出す方が合理的ですVERBOSE_MODE
  4. $?寿命は非常に短いです。いつもこんな結果が出ますね最近の注文。  だから、そうすれば
    もし  Gitがインストールされていることを確認する;その後
        printf "GITがインストールされていません。\n"
    その他
        printf "GIT が現在インストールされています。\n"
    フィリピン諸島
    GIT_INSTALLED = $?
    次にGIT_INSTALLED終了ステータスを取得しますprintfGIT_INSTALLED事前に設定してください。
  5. あなたのテストは、if [[ ! $(git --version) ]]; then「戻りコード」(あなたの質問で言及されているように)をテストするのではなく、git --version標準出力に記録されているものがあるかどうかをテストすることです。これはあなたが望むものかもしれません。これがgitインストールされているかどうかをテストする最良の方法です。ただし、コマンドの終了ステータスを確認する方が良いかもしれません(通常は良いかもしれません)。
  6. スタイル注:if「本物」の部分が最初に来ると、文を理解するのは簡単ですthenelseあなたのスクリプトは次のように言います
    Gitがインストールされていない場合
    それから
        インストールされていないそうです。
    そうでない場合(つまり、いいえインストールされていません)
        すでにインストールされていると言います。
    フィリピン諸島
    二重否定は混乱しています。
  7. そしてそうです。exec 2> /dev/null42個の連続した文の標準エラーを抑制したい場合に便利です。単一のコマンドにのみ影響を与える必要がある場合は、次のようにそのコマンドに2> /dev/null (または)を入力します。> /dev/null 2>&1より良い提案

答え2

コマンドは良く見えますが、ロジックがすべてのケースをカバーするわけではありません。continue実行時にディスクリプタは反転しません。

また、どのように動作するか、実際にどのように動作するかを分析します。

GIT_INSTALLED=$?

$?最後に実行されたコマンドの終了コード。デバッグを使用してこれをさらに詳しく見てください(set -x)。

さらに、初心者は静的テストスクリプトによって大きな利点を得ることができます。shellcheck.net

関連情報