Bash関数からブール値を返す


211

ファイルに特定のプロパティがあり、trueまたはfalseを返すかどうかをチェックするbash関数を記述したいと思います。その後、「if」のスクリプトで使用できます。しかし、私は何を返すべきですか?

function myfun(){ ... return 0; else return 1; fi;}

それから私はこのようにそれを使います:

if myfun filename.txt; then ...

もちろん、これは機能しません。どうすればこれを達成できますか?


3
functionキーワードを削除して、myfun() {...}十分
グレン・ジャックマン'25

2
重要なのifは、のゼロ終了ステータスですmyfun。でmyfun終了すると0then ...実行されます。それ以外の 場合else ...は実行されます。
Eelvex 2011年

7
@nhed:functionキーワードはバシズムであり、他のいくつかのシェルでは構文エラーを引き起こします。基本的に、それは不必要または禁止されているので、なぜそれを使うのですか?存在しない可能性があるため、grepターゲットとしても役立ちません(()代わりにgrep )。
Gordon Davisson 2013年

3
@GordonDavisson:何?他のシェルはありますか?;-)
2013年

0と1を参照するには使用しないでくださいstackoverflow.com/a/43840545/117471
ブルーノBronosky

回答:


333

trueの場合は0、falseの場合は1を使用します。

サンプル:

#!/bin/bash

isdirectory() {
  if [ -d "$1" ]
  then
    # 0 = true
    return 0 
  else
    # 1 = false
    return 1
  fi
}


if isdirectory $1; then echo "is directory"; else echo "nopes"; fi

編集する

@amichairのコメントから、これらも可能です

isdirectory() {
  if [ -d "$1" ]
  then
    true
  else
    false
  fi
}


isdirectory() {
  [ -d "$1" ]
}

4
いいえ、それを行う必要はありません-サンプルを参照してください。
エリック

46
読みやすくするために、「true」コマンド(何もせずに正常に完了する、つまり0を返す)と「false」コマンド(何もせずに正常に完了しない、つまりゼロ以外の値を返す)を使用できます。また、明示的なreturnステートメントなしで終了する関数は、最後に実行されたコマンドの終了コードを返すため、上記の例では、関数本体をのみに減らすことができます[ -d "$1" ]
amichair 2013年

24
ベンクト:それを「エラーコード」と考えるのは理にかなっています。エラーコード0 =すべてうまくいった= 0エラー。エラーコード1 =この呼び出しが行うことになっていた主なことは失敗しました。それ以外の場合:失敗します!マンページで調べてください。
空飛ぶ羊

7
プログラミングでは、通常、成功する方法は1つだけですが、無限に失敗する可能性があると考えると、理にかなっています。おそらく無限ではないかもしれませんが、多くの場合、オッズは私たちに対して積み重ねられています。成功/エラーはブール値ではありません。これは「trueの場合は0、falseの場合は1を使用する」と思います。「成功した場合は0を使用し、失敗した場合は0以外を使用する」と表示されます。
ダボス2017

6
0と1を参照するには使用しないでくださいstackoverflow.com/a/43840545/117471
ブルーノBronosky

167

250以上の賛成投票があるにもかかわらず、私が言うことを気にかけるべき理由

それはことはありません0 = true1 = false。これは、次のとおりです。ゼロ手段なし失敗(成功)ゼロ以外の手段の故障(タイプNの)

一方で選択した答えは技術的には「真」であるください入れないreturn 1ために、あなたのコードで** 。いくつかの残念な副作用があります。

  1. 経験豊富な開発者は、あなたをアマチュアとして見つけます(以下の理由により)。
  2. 経験豊富な開発者はこれを行いません(以下のすべての理由により)。
  3. エラーが発生しやすいです。
    • 経験豊富な開発者でさえ、(上記の理由により)0と1をそれぞれfalseとtrueと間違えることがあります。
  4. 無関係でばかげたコメントが必要です(または奨励されます)。
  5. 実際には、暗黙の戻りステータスほど役に立ちません。

バッシュを学ぶ

bashのマニュアルは言う(強調鉱山)

戻る[n]

シェル関数に実行を停止させ、値nを呼び出し元に返します。nが指定されていない場合、戻り値は、関数で最後に実行されたコマンドの終了ステータスです

したがって、TrueとFalseを示すために0と1を使用する必要はありません。彼らがそうするという事実は、コードのデバッグ、質問へのインタビュー、そして初心者の心を吹き飛ばすためにのみ役立つ本質的に些細な知識です。

bashのマニュアルにも書いてあります

それ以外の場合、関数の戻りステータスは、最後に実行されたコマンドの終了ステータスです。

bashのマニュアルにも書いてあります

$?最後に実行されたフォアグラウンドパイプライン終了ステータスに展開します。

ほら、待って。パイプライン?もう一度bashのマニュアルを見てみましょう。

パイプラインは、制御演算子 '|'の1つで区切られた1つ以上のコマンドのシーケンスです。または '|&'。

はい。彼らは、1つのコマンドはパイプラインであると述べました。したがって、これら3つの引用はすべて同じことを言っています。

  • $? 最後に何が起こったのかを教えてくれます。
  • 泡立ちます。

私の答え

したがって、@ Kambusはそのような単純な関数を使用してそれを実証しましたが、まったくreturn必要ありません。これを読むほとんどの人のニーズに比べると、非現実的に単純だったと思います。

なんでreturn

関数が最後のコマンドの終了ステータスを返す場合、なぜ使用returnするのですか?関数の実行を停止させるためです。

複数の条件下で実行を停止する

01  function i_should(){
02      uname="$(uname -a)"
03
04      [[ "$uname" =~ Darwin ]] && return
05
06      if [[ "$uname" =~ Ubuntu ]]; then
07          release="$(lsb_release -a)"
08          [[ "$release" =~ LTS ]]
09          return
10      fi
11
12      false
13  }
14
15  function do_it(){
16      echo "Hello, old friend."
17  }
18
19  if i_should; then
20    do_it
21  fi

ここにあるのは...

LHSがtrueの場合04&&のみRHS が実行されるため、行は明示的な[-ish]を返します。

ライン09はラインのステータスに一致するtrueまたはfalseを返します08

13が原因で行がfalseを返します12

(はい、これでゴルフをすることはできますが、例全体が工夫されています。)

別の一般的なパターン

# Instead of doing this...
some_command
if [[ $? -eq 1 ]]; then
    echo "some_command failed"
fi

# Do this...
some_command
status=$?
if ! $(exit $status); then
    echo "some_command failed"
fi

status変数を設定すると、の意味がわかりやすくなり$?ます。(もちろん$?、その意味はわかっていますが、いつかGoogleに習熟する必要のある知識が不足しています。コードで高頻度の取引を行わない限り、愛を示し、変数を設定してください。)しかし、本当の要点は「 「存在しないステータス」または逆に「終了ステータスの場合」を読み上げて、その意味を説明できます。ただし、最後の単語exitは、実際には$(...)サブシェルを終了しているときに、単語を見るとスクリプトを終了していると思われる可能性があるため、少し野心的すぎる可能性があります。


** return 1偽りの使用を絶対に主張する場合は、少なくともreturn 255代わりに使用することをお勧めします。これはあなたの将来の自分、またはあなたのコードを保守しなければならない他の開発者に「なぜ255なのか?」そうすれば、彼らは少なくとも注意を払い、間違いを回避できる可能性が高くなります。


1
@ZeroPhase 1&0 for false&trueはばかげています。バイナリデータ型がある場合、その理由はありません。bashで扱っているのは、成功(単数)と失敗(複数)を反映するステータスコードです。それは「ifこれを成功させること、elseそれを行うこと」です。何で成功?true / falseのチェック、文字列、整数、ファイル、ディレクトリ、書き込み権限、glob、regex、grep、またはその他の失敗の可能性のあるコマンドのチェックである可能性があります。
Bruno Bronosky 2017

3
それが鈍くて混乱しやすいという理由だけで、戻り値として0/1の標準的な使用を回避するのはばかげています。シェル言語全体は鈍く、混乱しがちです。Bash自体は、コマンドtruefalseコマンドで0/1 = true / false規則を使用しています。つまり、キーワードはtrue文字通り0のステータスコードに評価されます。さらに、if-thenステートメントは本来、成功コードではなくブール値で動作します。ブール演算中にエラーが発生した場合、trueまたはfalseを返さず、単に実行を中断する必要があります。そうしないと、誤検知(しゃれ)が発生します。
Beejor 2017

1
"if!$(exit $ status); then"-それはより良い説明に値します。直感的ではありません。メッセージを出力する前にプログラムが終了するかどうかを考えなければなりません。あなたの答えの残りは良かったが、それはそれを台無しにした。
Craig Hicks

1
@BrunoBronosky私はあなたの答えを読み、コンテンツパイプライン(stdin-> stdout)と戻り値のエラーコードの違いを理解していると思います。しかし、なぜ使用return 1を避けるべきなのかわかりません。私がvalidate関数を持っていると仮定するとreturn 1、検証が失敗した場合に合理的だと思います。結局のところ、それがスクリプトが適切に処理されない場合(たとえば、を使用する場合set -e)、スクリプトの実行を停止する理由です。
JepZ

1
@Jepzそれは素晴らしい質問です。あなたは正しいreturn 1です。私の懸念は、「0 = true 1 = falseは[否定的な単語を挿入]である」というコメントすべてです。それらの人々はいつかあなたのコードを読むでしょう。したがって、彼らが見るreturn 255(または42または2でさえ)ことは、それについてより深く考え、「本当」と誤解しないようにするのに役立ちます。set -eまだそれをキャッチします。
Bruno Bronosky


13

オプション-dのみでディレクトリをチェックするときは注意してください。
変数$ 1が空の場合、チェックは成功します。変数が空でないことも確認してください。

#! /bin/bash

is_directory(){

    if [[ -d $1 ]] && [[ -n $1 ]] ; then
        return 0
    else
        return 1
    fi

}


#Test
if is_directory $1 ; then
    echo "Directory exist"
else
    echo "Directory does not exist!" 
fi

1
これが尋ねられた質問にどのように答えるかについて、私は不確かです。空の$ 1が空のときにtrueを返すことができることを知っているのは良いことですが、bash関数からtrueまたはfalseを返す方法についての洞察はありません。「空のシェル変数でテストを行うとどうなりますか?」という新しい質問を作成することをお勧めします。そして、これを答えとして投稿します。
DRaehal 14

3
$1"$1")に適切な引用符を追加すると、空の変数を確認する必要がないことに注意してください。[[ -d "$1" ]]これがため、失敗し""たディレクトリではありません。
報道関係者、2016年

3

私はつまずいていた点(明示的にはまだ言及されていませんか?)に遭遇しました。つまり、ブール値を返す方法ではなく、ブール値を正しく評価する方法です。

と言おうとしたのですがif [ myfunc ]; then ...、それは間違いです。括弧は使用しないでください。if myfunc; then ...それを行う方法です。

@Brunoおよびその他のとおり改めて表明し、trueかつfalseあるコマンドではなく、値!これは、シェルスクリプトのブール値を理解する上で非常に重要です。

この投稿では、ブール変数を使用して説明とデモを行いました:https : //stackoverflow.com/a/55174008/3220983。密接に関連しているので、チェックすることを強くお勧めします。

ここでは、関数からブール値を返し、評価する例をいくつか示します。

この:

test(){ false; }                                               
if test; then echo "it is"; fi                                 

エコー出力を生成しません。(つまり、falseをfalse 返します)

test(){ true; }                                                
if test; then echo "it is"; fi                                 

生成する:

it is                                                        

(つまり、trueをtrue 返します)

そして

test(){ x=1; }                                                
if test; then echo "it is"; fi                                 

生成する:

it is                                                                           

0(つまりtrue)が暗黙的に返されたためです。

さて、これは私を台無しにしていたものです...

test(){ true; }                                                
if [ test ]; then echo "it is"; fi                             

生成する:

it is                                                                           

そして

test(){ false; }                                                
if [ test ]; then echo "it is"; fi                             

ALSOは以下を生成します。

it is                                                                           

ここでブラケットを使用すると、誤検知が発生しました。(「outer」コマンドの結果は0だと思います。)

私の投稿の主な要点は次のとおりです。通常の等価性チェックの場合のように、ブール関数(または変数)を評価するために角かっこを使用しないでくださいif [ x -eq 1 ]; then...


2

使用するtrueか、falseすぐにあなたの前にコマンドをreturn、その後、returnパラメータなしで。return自動的にあなたの最後のコマンドの値を使用します。

への引数の指定returnは一貫性がなく、型固有であり、1または0を使用していない場合はエラーが発生しやすくなります。また、前のコメントで述べたように、ここで1または0を使用することは、この関数にアプローチする正しい方法ではありません。

#!/bin/bash

function test_for_cat {
    if [ $1 = "cat" ];
    then
        true
        return
    else
        false
        return
    fi
}

for i in cat hat;
do
    echo "${i}:"
    if test_for_cat "${i}";
    then
        echo "- True"
    else
        echo "- False"
    fi
done

出力:

$ bash bash_return.sh

cat:
- True
hat:
- False

1

これfunction myfun(){ ... return 0; else return 1; fi;}をこのように書き直すとうまくいくかもしれません function myfun(){ ... return; else false; fi;}。つまり、それがfalse関数の最後の命令である場合、関数全体で偽の結果が得られますが、returnとにかく真の結果で関数が中断されます。少なくとも私のbashインタープリターはそうだと思います。


1

関数の出力をテストするための最も短い形式は単純です

do_something() {
    [[ -e $1 ]] # e.g. test file exists
}

do_something "myfile.txt" || { echo "File doesn't exist!"; exit 1; }

1

コードの読みやすさの理由から、true / falseを返すと次のようになるはずです。

  • 一行に
  • 一つのコマンド
  • 覚えやすい
  • キーワードのreturn後に別のキーワードを続ける(trueまたはfalse

私の解決策はreturn $(true)またreturn $(false)は示されているとおりです:

is_directory()
{
    if [ -d "${1}" ]; then
        return $(true)
    else
        return $(false)
    fi
}

0

@Bruno Bronoskyと@mrteatimeをフォローアップして、ブールリターン "backwards"を記述するだけの提案をします。これは私が意味することです:

foo()
{
    if [ "$1" == "bar" ]; then
        true; return
    else
        false; return
    fi;
}

これにより、すべてのreturnステートメントの醜い2行の要件がなくなります。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.