Bash, если [false]; возвращает true

Обучался bash на этой неделе и столкнулся с проблемой.

#!/bin/sh

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

Это всегда будет выводить True, даже если условие, как представляется, указывает на другое. Если я удалю скобки [], тогда он будет работать, но я не понимаю, почему.

Ответ 1

Вы выполняете команду [ (aka test) с аргументом "false", а не выполняете команду false. Поскольку "false" является непустой строкой, команда test всегда выполняется успешно. Чтобы выполнить команду, отпустите команду [.

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

Ответ 2

Я обнаружил, что могу сделать базовую логику, выполнив что-то вроде:

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

Ответ 3

Использование 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

Ответ 4

Быстрый булевский грунт для Bash

Оператор if принимает команду как аргумент (как и &&, || и т.д.). Integer результирующий код команды интерпретируется как логический (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' 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)

Короче, если вы просто хотите что-то проверить как pass/fail (aka "true" / "false" ), затем передайте команду своим if или && и т.д. без скобок. Для сложных сравнений используйте скобки с соответствующими операторами.

И да, я знаю, что в Bash нет такой вещи, как собственный булев тип, и что if и [ и true являются технически "командами", а не "заявления"; это просто базовое, функциональное объяснение.