bashスクリプトで私のelifがelse文と見なされるのはなぜですか?

bashスクリプトで私のelifがelse文と見なされるのはなぜですか?

私はwgetを使用してREST APIを介してサーバーから情報を取得するbashスクリプトを作成しています。 getoptsを使用してスクリプトに提供されているオプションを解析し、ifステートメントを使用して指定されたオプションに従ってスクリプトを正しくリダイレ​​クトします。スクリプト本文(wget呼び出しなど)に移動すると、elifはヘルプメニューを印刷し、そうでない場合はエラーメッセージを出力します。しかし、私の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ワイルドカードパターンのリストとして解釈し、各パターンを「名前付き一致ファイルのリスト」に置き換えます。 1つのファイル名が一致します。」

help空白の場合は、[ -n $help ]3つの単語のリストに展開されます。なぜなら、空の文字列の分割+globの結果は空の単語リストであるからです。括弧の間に単語が1つしかない場合、その単語が空でない場合、条件はtrueです。空ではないため、条件はtrueです。[-n]-n

解決策は次のように書くことです[ -n "$help" ]。空の場合、help4つの単語、空の単語のリストに展開されます。これはnullワードに演算子を適用し、条件はfalseです。[-n]-n

別の解決策はを使用することです[[ -n $help ]]。二重括弧は解析規則が異なる特殊な構文です(一方、単一の括弧は興味深い名前の一般的なコマンドです)。ほとんどの場合、二重括弧内で、および=の右側を除いて、変数置換の周りに二重引用符を省略できます。必要に応じて、二重引用符の省略を許可する例外を覚えておく必要がないように作成できます。変数の置換の周りに常に二重引用符を追加することを覚えておいてください(そして、コマンドの置換の周りにも同様:)。==!==~[[ -n "$help" ]]"$(foo)"

答え3

  1. ここでは if/elif は必要ありません。使用法ヘルプを印刷してスクリプトを設定するのではなく、スクリプトを終了する関数を生成すると、-hオプションはその関数を呼び出すことができます。help=trueusage()-h

  2. grepまたは を使用して簡単に実行できるsedタスクを実行するために埋め込みPythonコードを使用するのはなぜですかawk?またはjq

  3. とにかくコードは機能しません。あなたはその意味について混乱しているようです$data。 helpとgetoptsのケースの説明によると、$datasave data/issueID....がURL fetchedを使用してコンテンツを保存すると仮定しているようですwget

    実際には、そのデータ/問題IDを使用していないようです-d。リクエストのクエリ文字列にこれを含める必要がありますか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

関連情報