web-dev-qa-db-ja.com

Bashスクリプト関数がTrue-Falseを返す

値を返すことで関数をクエリしたいのですが。私のコードは次のとおりです。

check(){
    file=/root/Turkiye.txt
    local funkx=$1
    while read line; do
        if [ "$line" == "$funkx" ]
        then
            true
            break
        else
            false
        fi
    done < $file
}

printf "Please enter the value : "
read keyboard

if check $keyboard;
then
    echo "yes";
else
    echo "no";
fi

それは機能しません、何が間違っていますか?

4
Oğuz

trueおよびfalseは、それぞれ成功および失敗の終了コードで終了するコマンドです。これらは、returnコマンドを使用して関数にこれらの値を返させず、成功(0)または失敗(0以外)に対応する整数値を返します。また、no行が一致した場合でも、一致しない最初の行の失敗を返さないようにしたいと思います。

check(){
    file=/root/Turkiye.txt
    local funkx=$1
    while read line; do
        if [ "$line" == "$funkx" ]
        then
            return 0    # 0 = success ("true"); break is not needed because return exits the function
        fi
    done < $file
    # If a line matched, it won't get here (it will have returned out of the middle
    # of the loop). Therefore, if it gets here, there must not have been a match.
    return 1    # 1 = failure ("false")
}

しかし、これを行うにはもっと簡単な方法があります。 grepを使用します-その仕事は、一致する行のファイルを検索することです。あなたが欲しいgrep -Fxq--Fは、(正規表現パターンではなく)固定文字列を検索することを意味し、-xは、行の一部ではなく行全体が一致する必要があることを意味し、-qは、結果を出力せずに、一致が見つかった場合は成功ステータスで終了し、それ以外の場合は失敗することを意味します。また、関数は暗黙的にreturnコマンドを必要としません。これは、関数がその中の最後のコマンドのステータスを暗黙的に返すためです。

check(){
    file=/root/Turkiye.txt
    local funkx=$1
    grep -Fxq "$funkx" "$file"
}

またはさらに簡単:

check(){
    grep -Fxq "$1" /root/Turkiye.txt
}
6
Gordon Davisson

別のファイルでコードをテストすると、それはdoesは、たとえそれが少し非効率的であっても、実際に機能します。 _/root/Turkiye.txt_ファイルが空ではないファイルであると想定すると、trueおよびfalse呼び出しは、関数で実行される最後のコマンドであるため、関数の終了ステータスをいずれかのゼロに設定しますまたはゼロ以外。

単に、読み込んでいるファイルの別の行として見つからない文字列をスクリプトに入力している可能性があります。残念ながら、解析しているファイルがどのように見えるか、スクリプトにどのように入力しているのか、そうするときにスクリプトからの応答として何が期待できるのかは、質問ではわかりません。

_while read line_は必ずしも入力ファイルからlinesを読み取るとは限らないことにも注意してください。たとえば、 " " IFS = read -r line " "の理解、および_[ ... ]_内の2つの文字列を比較する演算子は_=_であり、_==_ではありません。

また、Wordの分割とファイル名の生成(グロビング)を回避するために、checkの呼び出しで_$keyboard_を二重引用符で囲む必要があります。


関数を使用して、ユーザーから読み取られた文字列が特定のファイルの行として出現するかどうかを判断するように見えます。

これは簡単に行うことができます

_grep -qxF -e "$keyboard" /root/Turkiye.txt
_

このgrepコマンドは、指定されたファイルで文字列を検索し、まったく同じ行が見つかった場合、ゼロの終了ステータス(true)を返します。それ以外の場合は、ゼロ以外の終了ステータス(false)を返します。ここで使用されるオプションは、_-q_を使用してgrepに何も出力しないようにし、_-x_を使用して完全な行(部分文字列ではない)を比較し、_-F_を使用して文字列比較を行います(正規表現では一致しません)。 _-e_は、次の引数が検索パターンであることをgrepに通知します(パターン内の最初の_-_は、コマンドラインオプションの導入と見なされます)。

変更されたスクリプト:

_printf 'Please enter the value: ' >&2
IFS= read -r keyboard

if grep -qxF -e "$keyboard" /root/Turkiye.txt; then
    echo 'yes'
else
    echo 'no'
fi
_

ユーザーが文字列を入力するためのプロンプトを標準エラーストリームに出力することに注意してください。これは慣例によるものであり、プロンプトを含まずにスクリプトの出力をリダイレクトして使用することができます。

bashでは、あなたは

_IFS= read -r -p 'Please enter the value: ' keyboard
_

(_read -p_を使用すると、bashも標準エラーストリームにプロンプ​​ト文字列を出力することに注意してください。)

関数でgrepを使用する場合:

_check () {
    grep -qxF -e "$1" /root/Turkiye.txt
}
_

次に使用します

_if check "$keyboard"; then
    echo 'yes'
else
    echo 'no'
fi
_
3
Kusalananda