如果[false]则重击;返回true


151

这周一直在学习bash并遇到障碍。

#!/bin/sh

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

即使条件似乎表明并非如此,这也将始终输出True。如果我卸下支架,[]那么它可以工作,但我不明白为什么。


3
这是一些可以帮助您入门东西。
键盘手

10
顺便说一句,以开头的脚本#!/bin/sh不是bash脚本,而是POSIX sh脚本。即使您的系统上的POSIX sh解释器由bash提供,它也会关闭大量扩展。如果您想编写bash脚本,请使用#!/bin/bash或其本地等效的脚本(#!/usr/bin/env bash以使用PATH中的第一个bash解释器)。
Charles Duffy 2015年

[[ false ]]也会影响。
CMCDragonkai 2015年

Answers:


190

您正在使用参数“ false” 运行[(aka test)命令,而不是运行command false。由于“ false”是一个非空字符串,因此test命令始终成功。要实际运行该命令,请删除该[命令。

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

4
错误地认为是命令,甚至是字符串的想法,对我来说似乎很奇怪,但我想它是可行的。谢谢。
2013年

31
bash没有布尔值数据类型,因此没有关键字代表真和假。该if语句仅检查您给出的命令是成功还是失败。该test命令接受一个表达式,如果表达式为true,则成功;否则,该命令将失败。与其他大多数编程语言一样,非空字符串是一个计算结果为true的表达式。false是一个总是失败的命令。(以此类推,这true是一条永远成功的命令。)
chepner

2
if [[ false ]];也返回true。一样if [[ 0 ]];。并且if [[ /usr/bin/false ]];也不跳过该块。false或0如何计算为非零?该死的令人沮丧。如果重要,请使用OS X 10.8;重击3.
jww

7
不要误认为false布尔常量或0整数文字。两者都是普通的字符串。[[ x ]]等效[[ -n x ]]于所有x不以连字符开头的字符串。在任何上下文中bash都没有任何布尔常量。看起来像整数的字符串在内部(( ... ))使用此类,-eq-lt在或内部使用运算符[[ ... ]]
chepner

2
@ tbc0,除了阅读内容之外,还有更多的担忧。如果变量不是由您完全控制的代码设置的(或者可以由外部操作,可以通过不寻常的文件名或其他方式进行设置),if $predicate则很容易被滥用以无法执行恶意代码的方式if [[ $predicate ]]
Charles Duffy

55

Bash的快速布尔入门

if声明需要一个命令作为参数(如做&&||等)。命令的整数结果代码被解释为布尔值(0 / null = true,1 / else = false)。

test语句将运算符和操作数作为参数,并以与相同的格式返回结果代码iftest语句的别名是[,通常用于if执行更复杂的比较。

truefalse语句什么也不做,返回的结果代码(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'vs.之类的操作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”),则将命令传递给您的ifor &&等语句,不带括号。对于复杂的比较,请使用带有适当运算符的方括号。

是的,我知道Bash中不存在本机布尔类型,并且ifand [true从技术上讲是“命令”而不是“语句”。这只是一个非常基本的功能说明。


1
仅供参考,如果您想在代码中使用1/0作为True / False,则if (( $x )); then echo "Hello"; fi显示消息for x=1而不是for x=0x=(未定义)。
乔纳森·H

3

我发现可以通过运行以下命令来执行一些基本逻辑:

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

6
一个可以,但这是一个非常糟糕的主意。( $A && $B )这是一个令人惊讶的低效操作-您通过调用产生一个子进程fork(),然后将其内容进行字符串拆分$A以生成元素列表(在这种情况下为size),并将每个元素评估为一个glob(在这种情况下为会对其求值),然后将结果作为命令运行(在这种情况下为内置命令)。
Charles Duffy

3
而且,如果您的truefalse字符串来自其他地方,则存在它们实际上可能包含true或以外的内容的风险false,并且您可能会得到意外的行为,包括任意命令执行。
查尔斯·达菲

6
编写和-将它们视为数字-或,将空字符串视为false和将非空字符串视为true 则要安全得多。A=1; B=1if (( A && B ))[[ $A && $B ]]
Charles Duffy

3
(请注意,我仅使用以上全大写字母的变量名来遵循答案建立的约定-POSIX实际上明确指定了用于环境变量和shell内置函数的全大写字母名,并保留小写名称供应用程序使用;为了避免与将来的OS环境发生冲突,特别是考虑到设置shell变量会覆盖任何同名的环境变量,因此始终最好在自己的脚本中遵守该约定)。
Charles Duffy

感谢您的见解!
罗德里戈

2

使用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

我发现这很有用,但是在ubuntu 18.04中,$ 0是“ -bash”,并且basename命令抛出错误。更改测试以[[ "$0" =~ "bash" ]] 使脚本适合我。
WiringHarness
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.