W tym tygodniu uczyłem się bash i wpadłem w kłopoty.
#!/bin/sh
if [ false ]; then
echo "True"
else
echo "False"
fi
To zawsze wyświetli wartość True, nawet jeśli warunek wydaje się wskazywać inaczej. Jak zdejmę nawiasy []
to działa, ale nie rozumiem dlaczego.
bash
conditional-operator
tenmiles
źródło
źródło
#!/bin/sh
nie jest skryptem bash - to skrypt sh POSIX. Nawet jeśli interpreter POSIX sh w twoim systemie jest dostarczany przez bash, wyłącza on kilka rozszerzeń. Jeśli chcesz pisać skrypty basha, użyj#!/bin/bash
lub jego lokalnego odpowiednika (#!/usr/bin/env bash
aby użyć pierwszego interpretera basha w PATH).[[ false ]]
też ma wpływ .Odpowiedzi:
Uruchamiasz polecenie
[
(akatest
) z argumentem „false”, a nie uruchamiasz poleceniefalse
. Ponieważ „false” nie jest pustym łańcuchem,test
polecenie zawsze się powiedzie. Aby faktycznie uruchomić polecenie, upuść[
polecenie.źródło
bash
nie ma typu danych Boolean, więc nie ma słów kluczowych reprezentujących prawdę i fałsz.if
Oświadczenie jedynie sprawdza, czy rozkaz dasz się powiedzie lub nie.test
Polecenie wykonuje wyrażenie i uda, jeśli wyrażenie jest prawdziwe; niepusty ciąg jest wyrażeniem, którego wynikiem jest prawda, tak jak w większości innych języków programowania.false
to polecenie, które zawsze zawodzi. (Analogicznie,true
to polecenie, które zawsze się udaje)if [[ false ]];
zwraca też prawdę. Tak jakif [[ 0 ]];
. Iif [[ /usr/bin/false ]];
nie pomija też bloku. W jaki sposób wartość false lub 0 może być różna od zera? Cholera, to frustrujące. Jeśli to ma znaczenie, OS X 10.8; Bash 3.false
ze stałą logiczną lub0
literałem całkowitoliczbowym; oba to zwykłe struny.[[ x ]]
jest równoważne[[ -n x ]]
dla dowolnego ciągux
, który nie zaczyna się od łącznika.bash
nie ma żadnych stałych boolowskich w żadnym kontekście. Łańcuchy, które wyglądają jak liczby całkowite, są traktowane jako takie wewnątrz(( ... ))
lub z operatorami takimi jak-eq
lub-lt
inside[[ ... ]]
.if $predicate
można je łatwo wykorzystać do wykonania wrogiego kodu w sposób, któryif [[ $predicate ]]
nie może.Quick Boolean Primer for Bash
if
Oświadczenie wykonuje polecenie jako argument (jak zrobić&&
,||
itp). Całkowity kod wyniku polecenia jest interpretowany jako wartość logiczna (0 / null = prawda, 1 / else = fałsz).test
Oświadczenie bierze operatorów i operandów jako argumenty i zwraca kod wynikowy w takim samym formacie jakif
. Aliastest
instrukcji to[
, który jest często używanyif
do wykonywania bardziej złożonych porównań.Instrukcje
true
ifalse
nic nie robią i zwracają kod wyniku (odpowiednio 0 i 1). Można ich więc używać jako literałów logicznych w Bash. Ale jeśli umieścisz instrukcje w miejscu, w którym są interpretowane jako ciągi, napotkasz problemy. W Twoim przypadku:Więc:
Jest to podobne do zrobienia czegoś podobnego
echo '$foo'
vs.echo "$foo"
.W przypadku użycia
test
instrukcji wynik zależy od użytych operatorów.Krótko mówiąc , jeśli po prostu chcesz przetestować coś jak pass / fail (aka „true” / „false”), a następnie przejść do polecenia
if
lub&&
itp oświadczenie, bez nawiasów. W przypadku złożonych porównań użyj nawiasów z odpowiednimi operatorami.I tak, zdaję sobie sprawę że nie ma czegoś takiego jak natywny typu boolean w bash, a
if
i[
itrue
są technicznie „polecenia”, a nie „oświadczenia”; to tylko bardzo podstawowe, funkcjonalne wyjaśnienie.źródło
if (( $x )); then echo "Hello"; fi
pokazuje komunikat dla,x=1
ale nie dlax=0
lubx=
(nieokreślony).Odkryłem, że mogę wykonać podstawową logikę, uruchamiając coś takiego:
źródło
( $A && $B )
jest zaskakująco nieefektywną operacją - tworzysz podproces poprzez wywołaniefork()
, a następnie dzielisz zawartość na łańcuchy w$A
celu wygenerowania listy elementów (w tym przypadku o rozmiarze jeden) i oceniasz każdy element jako glob (w tym przypadku jeden która ocenia siebie), a następnie uruchamia wynik jako polecenie (w tym przypadku polecenie wbudowane).true
ifalse
ciągi znaków pochodzą z innego miejsca, istnieje ryzyko, że mogą faktycznie zawierać zawartość inną niżtrue
lubfalse
, i możesz uzyskać nieoczekiwane zachowanie, włącznie z wykonaniem dowolnego polecenia.A=1; B=1
iif (( A && B ))
- traktowanie ich jako liczb - lub[[ $A && $B ]]
, które traktują pusty ciąg jako fałsz, a niepusty ciąg jako prawdziwy.Używanie prawda / fałsz usuwa trochę bałaganu w nawiasach ...
źródło
[[ "$0" =~ "bash" ]]
skrypt działał dla mnie.