为什么我的 elif 在 bash 脚本中被视为 else 语句?

为什么我的 elif 在 bash 脚本中被视为 else 语句?

我正在构建一个 bash 脚本,该脚本使用 wget 通过 REST api 从服务器获取信息。我使用 getopts 解析提供给脚本的选项,然后使用 if 语句根据给定的选项正确重定向脚本。 if 转到脚本的主体(即 wget 调用),elif 打印帮助菜单,else 打印错误消息。然而我的 elif 似乎充当了 else 语句。当我跑步时:

>./jira -h

我得到了正确的响应,即帮助菜单:

----------jira options----------
Required:
-d [data/issueID]
-u [username] -> [username] is your JIRA username
-p [password] -> [password] is your JIRA password

Optional:
-q -> quiet, i.e. no output to console
-h -> help menu

然而,当我运行一些应该给我错误消息的东西时,我会得到帮助菜单:

>./jira -u jsimmons

----------jira options----------
Required:
-d [data/issueID]
-u [username] -> [username] is your JIRA username
-p [password] -> [password] is your JIRA password

Optional:
-q -> quiet, i.e. no output to console
-h -> help menu 

我的脚本如下:

#!/bin/bash

#using getopts to parse options
while getopts ":hqd:u:p:" opt; do
        case $opt in
                h)
                        help="true"
                        ;;      
                q)
                        quiet="true"
                        ;;      
                d)
                        data=$OPTARG
                        ;;
                u)
                        username=$OPTARG
                        ;;
                p)
                        password=$OPTARG
                        ;;
                \?)
                        echo "Invalid option: -$OPTARG" >&2
                        ;;
                :)
                        echo "Option -$OPTARG requires an argument." >&2
                        ;;
        esac
done

#check if required options have been set
if [[ -n $data && -n $username && -n $password ]]; then 

        wget -q \
            --http-user=$username \
            --http-passwd=$password \
            --header="Content-Type: application/json" [URI]


        #placing issue info into variable

        response=$(< $data) 


        #using heredoc to run python script
        #python script uses regular expressions to find the value of the field 
        #customfield_10701 ie the branch version 

        output=$(python - <<EOF
import re

matchObj = re.search(
     r'(?<=customfield_10701":").*(?=","customfield_10702)',
     '$response',
     re.I
)
if(matchObj):
        print(matchObj.group())

EOF
)


        #writes branch version in .txt file

        echo $output>branchversion.txt 


        #prints the branch version if the quiet option hasn't been set 
        if [ -z $quiet ]; then
                echo "-------------------------------------------" 
                echo ""
                echo "The branch version for issue $data is:"
                cat branchversion.txt
                echo ""
        fi

        #removes file that wget creates containing all data members for the issue

        rm $data
elif [ -n $help ]; then 
        #if help option has been set    
        echo "" 
        echo "----------jira options----------"
        echo "Required:"
        echo "-d [data/issueID]"
        echo "-u [username] -> [username] is your JIRA username"
        echo "-p [password] -> [password] is your JIRA password"
        echo ""
        echo "Optional:"
        echo "-q -> quiet, i.e. no output to console"
        echo "-h -> help menu"
        echo ""
        #http GET data members for issue
else
        #if not all required options or help have been set      
        echo "Error: Missing argument(s)"
        echo "Usage: ./jira [option(s)] -d [data] -u [username] -p [password]"
        echo "" 
        echo "Try: ./jira -h for more options"
fi

答案1

-n选项检查字符串的长度是否非零。

if [ ... ]; then #posix compliant condition tests

if [[ ... ]]; then #extended condition tests

扩展条件测试的工作方式似乎与 posix 不同。

> if [ -n $unsetVar ];then echo yes ; fi
yes
>

> if [ -n "$unsetVar" ];then echo yes ; fi
>

> if [[ -n $unsetVar ]];then echo yes ; fi
>

要么对两者使用扩展条件[[ ... ]],要么将变量括在引号中。目前你的elif陈述总是正确的。

答案2

根本问题是您省略了变量替换周围的双引号。在大多数情况下,当您编写 时$help,这并不意味着“获取 的值help”,而是意味着“获取 的值help,将其解释为以空格分隔的通配符模式列表,并将每个模式替换为匹配文件的列表如果至少有一个文件名匹配,则命名”。

help为空时,展开为三个单词, ,[ -n $help ]的列表,因为对空字符串进行 split+glob 的结果是一个空单词列表。当括号之间只有一个单词时,除非该单词为空,否则条件为真。不为空,因此条件为真。[-n]-n

解决办法是这样写[ -n "$help" ]:当为空时,它会扩展到四个单词, , 空单词 ,help的列表。这将运算符应用于空字并且条件为假。[-n]-n

另一种解决方案是使用[[ -n $help ]].双括号是特殊的语法,具有不同的解析规则(而单括号是具有有趣名称的普通命令)。在大多数情况下,在双括号内,您可以在变量替换周围省略双引号,但 、=和的右侧除外。如果您愿意,您可以编写,因此您不需要记住允许省略双引号的例外情况:只需记住始终在变量替换周围添加双引号(以及类似地在命令替换周围添加双引号:)。==!==~[[ -n "$help" ]]"$(foo)"

答案3

  1. 这里甚至不需要 if/elif 。创建一个打印使用帮助并退出脚本的函数,而不是-h设置,然后该选项就可以调用该函数。help=trueusage()-h

  2. grep为什么你使用嵌入式 python 代码来完成可以更轻松地使用or完成的sed工作awk?或者jq

  3. 无论如何你的代码都不会工作。你似乎对其中的含义感到困惑$data。根据帮助和 getopts case 语句,$data保存data/issueID....但看起来您假设它保存使用 获取的 URL 的内容wget

    事实上,看起来您甚至没有使用该-ddata/issueID...也许您应该将其包含在请求的查询字符串中wget

    或者-d应该有一个文件名作为参数?从帮助信息来看,这似乎不太可能。


无论如何,这是一个解决了大部分问题的版本(并且,在我看来,大大提高了脚本的可读性):

#!/bin/bash

URI='...whatever...'

usage() {
# print optional error message and help message and exit.

[ -z "$*" ] || printf "%s\n\n" "$*"
# or, if you don't want help printed with every error message:
# [ -z "$*" ] || printf "%s\n\nUse -h option for help.\n" "$*" && exit 1

cat >&2 <<__EOF__
----------jira options----------
Required:
  -d [data/issueID]
  -u [username] -> [username] is your JIRA username
  -p [password] -> [password] is your JIRA password

Optional:
  -q -> quiet, i.e. no output to console
  -h -> help menu
__EOF__

exit 1
}

quiet=''

#using getopts to parse options
while getopts ":hqd:u:p:" opt; do
  case $opt in
     h) usage ;; 
     q) quiet='true' ;;     
     d) data="$OPTARG" ;;
     u) username="$OPTARG" ;;
     p) password="$OPTARG" ;;
    \?) usage "Invalid option: -$OPTARG" ;;
     :) usage "Option -$OPTARG requires an argument." ;;
  esac
done

# check for required options

[ -z "$data" ]     && usage '-d is required'
[ -z "$username" ] && usage '-u is required'
[ -z "$password" ] && usage '-p is required'

# your embedded python overkill could easily be done with `sed`
# or `awk`.   or maybe `jq` as the wget output is json.
# but without a sample of the input I can't provide a guaranteed
# working example.  The awk script below is a first attempt at
# extracting the value of `customfield_10701`

wget -q --http-user="$username" \
        --http-passwd="$password" \
        --header='Content-Type: application/json' \
        -O -
        "$URI" |
  awk -F': ' '/"customfield_10701"/ {
                gsub(/[",]/,"",$2);
                print $2
              }' > branchversion.txt

# alternatively, if you have `jq` installed, try piping wget's
# output through something like `jq -r .customfield_10701` instead of awk.

#prints the branch version if the quiet option hasn't been set
if [ -z "$quiet" ]; then
  echo "-------------------------------------------"
  echo ""
  echo "The branch version for issue $data is:"
  cat branchversion.txt
  echo ""
fi

相关内容