Bashスクリプトのコマンドオプションの解析

Bashスクリプトのコマンドオプションの解析

私は "高速"スクリプトを書いてから、メールスイッチ(エコーからパイプされる構文)をオフにするために "--nomail"オプションを追加することを検討しました。

私はそれが簡単だと思いましたが、基本的に元のスクリプトをうまく設定していないので、この「オプション」は私を殺しました。

Bashの新機能です...ありがとう!

私の素晴らしい仕事スクリプト! :

 ## Current threshold value setting
 THRESHOLD="80"                                      

 ## Input Files and Mailx
 LOCATIONS="fsIn.txt"                                               ## Edit "fsIn.txt" to add or change filesystems
 TOLIST="$(cat toList.txt | tr -s '\n' ' ' )"                       ## Sets who receives email if an error condition exists
 REPLYTO="$(cat replyTo.txt | tr -s '\n' ' ' )"                     ## sets the reply to email addresses
 FROM=”SCRIPT TEAM"                             ## Sets the "from" address on error emails
 SUBJECT="$HOST: ! STORAGE LEVEL MET OR EXCEEDED !"         ## Sets the subject line
 ############

 for i in $(cat $LOCATIONS)

 do

 ## Main df pipeline to return usage percentage
 CAP=$(df -PH --no-sync "$i" | awk 'NR>1'| awk {'print $5'} | sed 's/.$//')

for i in $(cat $LOCATIONS)                  #Several different file system locations are ‘catted’ in here .  E.g.  /dev

do

## Main df pipeline to return usage percentage to stdout and piped to mailx
CAP=$(df -PH --no-sync "$i" | awk 'NR>1'| awk {'print $5'} | sed 's/.$//')
        if [ $CAP -ge $THRESHOLD ]
            then
           (echo                               
            echo "---------- CAPACITY TEST FAILED ---------- "
            echo -n "  SYSTEM NAME: " ; uname -n
            echo -n "  USER DETAIL: " ; whoami
            echo "  TEST AREA:   $i "
            echo "  USED SPACE:  $CAP% "
            echo "  THRESHOLD:   $THRESHOLD% "
            echo "  !!!!!! THRESHOLD EXCEEDED !!!!!! ") | tee >(mailx -s "$SUBJECT" -r "$FROM" -S replyto="$REPLYTO" "$TOLIST")
            echo

        else
            echo
            echo "++++++++++ CAPACITY TEST PASSED ++++++++++ "
            echo "  TEST AREA:   $i "
            echo "  USED SPACE:  $CAP% "
            echo "  THRESHOLD:   $THRESHOLD% "
            echo " !!! SUCCESS SUCCESS SUCCESS SUCCESS !!! "
            echo
    fi

done

exit 0

これは非常にうまく動作します!しかし、--nomailオプションを含めるように再設定する方法がわかりません。 「事例」は慎重だと思われますが、ここでは迷子になりました。

どんなアイデアがありますか?

とても感謝しています!

答え1

簡単な答えは2つあります。

  • send_emailtoなどのフラグを設定し、true電子メール抑制パラメータがある場合は、それを無効にするか、falseに設定します。
  • 出力になる変数または一時ファイルを組み合わせてから、実際の電子メール転送を関数呼び出しに渡して事前に電子メールを作成します。

たとえば、

send_email="true"
handle_email() {
    echo "$email_body" | mailx -s "$subject" -r "$from" -S replyto="$replyto" ${recipients[@]}
}

[...]
if [[ "--nomail" == "$1" ]]; then
    send_email=false
fi
[...]
if [[ true == "$send_email ]]; then
    handle_email
fi

答え2

修正する

私は戻ってあなたの質問全体を読んで、もともとあなたが要求したものとは少し異なる質問に答えたことに気づきました。だからここにあります:

  1. あなたの構造は素晴らしいです。スクリプトの先頭でコマンドオプションを解析します。

  2. caseはい、ステートメントを使用して確認できます$1(下記の元の回答を参照)。ただし、1つのオプションのみを計画している場合は、単一のテストを簡単に実行できます(下記の元の回答を参照)。caseいくつかの可能なオプションを含むステートメントを使用するには、そのコマンドをwhileコマンドラインの次の単語/オプションに置き換えます。while "$1" ; do case ... esac; shift; doneshift$1

元の答え

この問題を解決する方法はいくつかあります。これが唯一のオプションである場合、またはいくつかのオプションがある場合は、手動で手動で解析することを検討できます。シェル言語では、シェルコマンドの後に続くすべての単語をシェルと呼びます。パラメータ、そしてそれぞれ位置パラメータ、フォームは1$nから始まりますn。したがって、テストを実行して問題が発生していることを確認し、[[ $1 == "--nomail" ]]それに応じて対処することができます。これはオプションが1つしかないシンプルで簡単な方法です。

getoptsオプションが多いより複雑なシェルスクリプトの場合は、特定の形式のコマンドを使用してオプションを解析する必要があるかもしれません。シェルには組み込みバージョンがbash含まれており、コマンドラインにthen(デフォルトのポケットベルが設定されている場合)を入力して詳細を確認できます。getoptsman bashless/^ *getopt

答え3

他の回答では、すでにコマンドラインオプションを使用する方法について言及しています(つまり、"$1"直接確認または使用getopts)。私の答えは、--nomailスクリプトを最初から書き直さずにオプションを使用するようにスクリプトをすばやく変更する方法です。シェルスクリプティング技術と知識の進歩的な向上を活用するには、長期的にこれを行う必要があります。

最も明白な方法は、変数または一時ファイルを使用して印刷したい出力を保存または印刷してメールに送信し、それを毎回処理する方法を選択することです。

あまり明白ではない方法は、パイプを標準入力か、単に入力かをtee >(mailx ...)決定する関数呼び出しのパイプに置き換えることです。このアプローチでは、出力を保存する必要はなく、出力をパイプして関数が処理するようにします。残りのコードは知ったり気にする必要はありません(そして最も重要なことは処理するために書く必要はありません)。どちらの場合も)。teemailxcat

それはすべて...

まず、スクリプトの先頭の近くに次のコードを追加します。

# set the default, i.e. to send mail.
send_email=1

# Very basic option processing. Using getopts would be better.
[ "$1" == "--nomail" ] && send_email=''

myoutput() {
  if [ "$send_email" ] ; then
    # print stdin to stdout AND mail it
    tee <(mailx -s "$SUBJECT" -r "$FROM" -S replyto="$REPLYTO" "$TOLIST")
  else 
    # only print stdin to stdout. no mail.
    cat
  fi
}

次に、| tee ...ループ内で置き換えて、ここで定義された関数を使用します。for| myoutput

myoutput不都合な関数名です。名前を変更するcat_or_mailか、最も理解しやすい名前に変更してください。)

理想的には、関数はグローバル変数に依存するのではなくパラメータを受け入れる必要があり、次のように書く必要があります。

myoutput() {
  local send_email SUBJECT FROM REPYLTO TOLIST

  # more of the primitive option handling.  getopts can and should be used
  # inside a function too.    
  send_email="$1"
  SUBJECT="$2"
  FROM="$3"
  REPLYTO="$4"
  TOLIST="$5"

  # add code here to check if those variables contain valid values.
  # print warnings and/or abort and/or set appropriate defaults if they don't.

  if [ "$send_email" ] ; then
    # print stdin to stdout AND mail it
    tee <(mailx -s "$SUBJECT" -r "$FROM" -S replyto="$REPLYTO" "$TOLIST")
  else 
    # only print stdin to stdout. no mail.
    cat
  fi
}

そして電話してください... | myoutput "$send_email" "$SUBJECT" "$FROM" "$REPLYTO" "$TOLIST"

これにより、グローバル変数を事前設定しなくても関数を再利用できます。必要な値で呼び出すだけです。

関連情報