验证bash脚本参数

3
我正在尝试做类似这样的事情,编写一个脚本以执行备份操作,如果备份失败。我将环境作为脚本的参数输入。
我不确定如何验证 $1 只包含一些预定义的值。 预定义的值应该是 tst、prd、qa、rpt。 有人可以提供帮助吗?
#!/bin/bash
ENVIRONMENT=$1 
BACKUPDATE=$(date +"%d_%m_%Y")
BACKUPFILE="$ENVIRONMENT".backup."$BACKUPDATE".tar.gz

if [ $1 ==  "" ] 
 then
 echo "No environment specified"
 exit
elif [ -f "$BACKUPFILE" ]; then
   echo "The file '$BACKUPFILE' exists."
else
   echo "The file '$BACKUPFILE' in not found."
   exec touch "$BACKUPFILE"
fi

第一个测试的一行代码:[[ -z "$1" ]] && echo "未指定环境" && exit 1。你不需要执行 exec touch,只需使用 touch 即可。 - Matthieu
2
@Matthieu 简洁版一行代码:: ${1:?未指定环境} - chepner
@chepner 我知道周围有些东西,谢谢!(另请参见 https://dev59.com/rmox5IYBdhLWcg3w6oj0 ) - Matthieu
1
[ "$1" = "" ],或者只是 [ -z "$1" ]。始终引用您的扩展,并且不要使用 ==;它在 test 的 POSIX 规范 中没有标准化。 - Charles Duffy
2个回答

3
你可以使用case:
case "$1" in
    tst) echo "Backing up Test style" ;;
    prd)
        echo "Production backup"
        /etc/init.d/myservice stop
        tar czf ...
        /etc/init.d/myservice start
        ;;
    qa) echo "Quality skipped" ;;
    rpt)
        echo "Different type of backup"
        echo "This could be another processing"
        ...
        ;;
    *)
        echo "Unknown backup type"
        exit 2
        ;;
esac

注意每个case结尾都有双冒号;;,以及方便使用的模式匹配
编辑:根据您的评论和@CharlesDuffy的建议,如果您想将所有有效选项放入数组中,并针对任何一个选项测试您的值(因此对于所有有效值具有相同的代码),则可以使用关联数组
declare -A valids=(["tst"]=1 ["prd"]=1 ["qa"]=1 ["rpt"]=1)
if [[ -z ${valids[$1]} ]] ; then
    echo "Invalid parameter value"
    # Any other processing here ...
    exit 1
fi
# Here your parameter is valid, proceed with processing ...

这是通过将一个值(这里是1,但在其他情况下可以是任何其他值)分配给每个有效的参数来实现的。因此,任何无效的参数都将为null,并且-z测试将被触发。
鸣谢他。

@runegjo 你可以在问题中编辑一个选项列表,我们会为您展示一些示例 :) 每个 case 表达式对应于可能的选择之一,并且您将相应的代码放在 );; 之间。 - Matthieu
2
顺便提一下,TLDP,尤其是ABS,在过时的信息和展示不良实践的示例方面有些臭名昭著。Wooledge BashGuide是专门编写的替代品,没有这些缺点。https://stackoverflow.com/tags/bash/info的“书籍和资源”部分中没有列出ABS的原因,请考虑链接到官方手册、[bash-hackers' wiki](https://wiki.bash-hackers.org)或指南。 - Charles Duffy
@CharlesDuffy,感谢您提供有价值的关于源代码的信息。我编辑了我的答案,并附上了一个链接到bash-hackers' wiki,我曾经在一段时间内经常使用它。 - Matthieu
@runegjo,我在编辑中添加了Charles Duffy的评论。看看这样是否更好。 - Matthieu
@CharlesDuffy 我使用了你的评论来编辑我的答案。如果你对自己的回答满意,我会撤销那个编辑。 - Matthieu

1

根据您拥有的不同值的数量,考虑使用case语句?它甚至允许使用通配符。

case $1 in
  (John)   printf "Likes Yoko\n";;
  (Paul)   printf "Likes to write songs\n";;
  (George) printf "Harrison\n";;
  (Ringo)  printf "Da drumma\n";;
  (*)      printf "Management, perhaps?\n";;
esac

另外,如果可能的话,您应该避免不可移植的bashisms,例如[[测试运算符(如果可以,请使用[,例如if [ "$1" = "John" ]; then ...; fi)。


2
@runegjo 最终取决于您:如果您知道在您的计算机上可用 bash(通常是这样),那么 [[ ]] 更加灵活且可以安全使用。 - Matthieu
1
@Matthieu 是的,初始的 ( 是可选的。我总是使用它,因为我(和vi)喜欢匹配的括号。 - Jens
1
@Jens,……bashisms?“[[”是ksh-ism,几乎所有扩展shell都采用了它,理由很充分;通过使解析器识别“[[”语法,可以实现[无法实现的功能(如glob匹配)和安全特性(如完全确定语法和数据之间的区别;而[必须将某些特性标记为过时以避免歧义)。 - Charles Duffy
1
@runegjo,针对关联数组(一些其他语言称为映射或哈希的数据结构),可以轻松快速地进行操作。对于常规的数字索引数组,您需要循环,这将效率低下得多。 - Charles Duffy
2
declare -A validValues=( ["validOne"]=1 ["validTwo"]=1 ["whatever"]=1 ); if [[ ${validValues[$myValue]} ]]; then echo "$myValue is listed as valid"; fi - Charles Duffy
显示剩余6条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接