web-dev-qa-db-ja.com

bash if [false]; trueを返します

今週bashを学んでいて、ひっかかった。

#!/bin/sh

if [ false ]; then
    echo "True"
else
    echo "False"
fi

条件がそうでないことを示している場合でも、これは常にTrueを出力します。ブラケット[]を削除すると機能しますが、理由はわかりません。

111
tenmiles

引数__falseを指定して[(別名test)コマンドを実行していますが、コマンドfalseは実行していません。 「false」は空でない文字列であるため、testコマンドは常に成功します。コマンドを実際に実行するには、[コマンドをドロップします。

if false; then
   echo "True"
else
   echo "False"
fi
147
chepner

Bashのクイックブール入門

ifステートメントは引数としてコマンドを受け取ります&&||などと同様)。コマンドの整数結果コードはブール値(0/null = true、1/else = false)として解釈されます。

testステートメントは演算子とオペランドを引数として取りますで、ifと同じ形式で結果コードを返します。 testステートメントのエイリアスは[です。これは、ifとともに使用され、より複雑な比較を実行します。

trueおよびfalseステートメントは何もせず、結果コードを返します(それぞれ0および1)。そのため、Bashでブールリテラルとして使用できます。しかし、文字列として解釈される場所にステートメントを配置すると、問題が発生します。あなたの場合:

if [ foo ]; then ... # "if the string 'foo' is non-empty, return true"
if foo; then ...     # "if the command foo succeeds, return true"

そう:

if [ true  ] ; then echo "This text will always appear." ; fi;
if [ false ] ; then echo "This text will always appear." ; fi;
if true      ; then echo "This text will always appear." ; fi;
if false     ; then echo "This text will never appear."  ; fi;

これは、echo '$foo'echo "$foo"のようなことを行うことに似ています。

testステートメントを使用する場合、結果は使用する演算子によって異なります。

if [ "$foo" = "$bar" ]   # true if the string values of $foo and $bar are equal
if [ "$foo" -eq "$bar" ] # true if the integer values of $foo and $bar are equal
if [ -f "$foo" ]         # true if $foo is a file that exists (by path)
if [ "$foo" ]            # true if $foo evaluates to a non-empty string
if foo                   # true if foo, as a command/subroutine,
                         # evaluates to true/success (returns 0 or null)

略して、何かを成功/失敗(別名「true」/「false」)でテストしたい場合は、括弧なしでifまたは&&などのステートメントにコマンドを渡します。複雑な比較の場合は、適切な演算子で角括弧を使用します。

そして、はい、Bashにはネイティブのブール型のようなものは存在しないこと、そしてif[trueは技術的に「コマンド」であり、「ステートメント」ではないことを知っています。これは非常に基本的な機能説明です。

29
Beejor

私は次のようなものを実行することでいくつかの基本的なロジックを実行できることがわかりました。

A=true
B=true
if ($A && $B); then
    C=true
else
    C=false
fi
echo $C
3
Rodrigo

True/falseを使用すると、一部のブラケットクラッタが削除されます...

#! /bin/bash    
#  true_or_false.bash

[ "$(basename $0)" == "bash" ] && sourced=true || sourced=false

$sourced && echo "SOURCED"
$sourced || echo "CALLED"

# Just an alternate way:
! $sourced  &&  echo "CALLED " ||  echo "SOURCED"

$sourced && return || exit
0
psh