解析 bash 脚本中的命令选项

解析 bash 脚本中的命令选项

我编写了“快速”脚本,然后考虑添加一个“—nomail”选项来关闭我的邮件开关(其语法是从 echo 中通过管道输入的)。

我认为这很容易,但我认为,从根本上来说,我没有很好地构建原始脚本,所以,这个“选项”正在杀了我。

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

一个简单的答案是双重的:

  • 设置一个标志,例如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(请参阅下面我的原始答案),尽管如果您只计划一个选项,您可以轻松地执行单个测试(请参阅下面我的原始答案)。要使用case具有多个可能选项的语句,请将其放在while循环中,格式为while "$1" ; do case ... esac; shift; done.该shift命令将替换$1为命令行中的下一个单词/选项。

原答案

有几种方法可以解决这个问题。如果这是唯一的选项,或者只有几个选项,您可以考虑自己手动解析。在 shell 语言中,shell 命令后面的所有单词都被称为参数,并且每个都被分配给一个位置参数,形式$nn1 开始。因此,您可以执行测试来检查是否[[ $1 == "--nomail" ]]并采取相应的操作。这是只有一个选项的简单直接的方法。

对于具有许多选项的更复杂的 shell 脚本,您可能需要利用某种形式的getopts命令来为您解析选项。 shellbash包含一个getopts内置版本,您可以通过man bash在命令行中键入然后(如果您的默认寻呼机设置为less)来了解有关它的更多信息/^ *getopt

答案3

其他答案已经提到如何采用命令行选项(即"$1"直接检查或使用getopts)。我的答案是如何快速修改脚本以使用选项,--nomail而无需从头开始重写脚本。从长远来看,您可能应该这样做,即使只是为了利用您的 shell 脚本技能和知识的逐步提高。

最明显的方法是使用变量或临时文件来存储要打印或打印和邮件的输出,然后每次选择如何处理它。

不太明显的方法是将管道 to 替换tee >(mailx ...)为函数调用的管道,该函数调用决定是tee其标准输入mailx还是仅是cat它。使用这种方法,不需要存储输出,只需通过管道传输并让函数处理它 - 其余代码不需要知道或关心(而且,最重要的是,不需要写入处理这两种情况)。

就是这样...

首先,在脚本开头附近的某个位置添加这样的代码:

# 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"

这使得该函数可以重复使用,而无需事先设置全局变量 - 只需使用您需要的值调用它即可。

相关内容