2010-09-26 15 views
11

dlaczego:bash czy z lub i negacja

#!/bin/bash 
wtf=false 
if [ $wtf ] || [ ! -f filethatexists.whatever ] 
then 
echo "WTF1" 
fi 
if [ ! -f filethatexists.whatever ] 
then 
echo "WTF2" 
fi 

wydruku:

WTF1

zamiast niczego? Jest to szczególnie kłopotliwe, że druga forma działa zgodnie z oczekiwaniami, a pierwsza nie.

Odpowiedz

10

Podstawowy test

[ $wtf ] 

sprawdza czy ciąg w środku jest pusta lub nie.

Od $wtf zawiera ciąg 'false' test zwraca prawdę lub stan exit 0 na sukces, ponieważ 'false' nie jest taka sama, jak ciąg pusty '' - i stąd można dostać WTF1 jako odpowiedź.

spróbuj:

wtf='' 

Jak podkreślił Gordon Davisson (i Dennis Williamson), to jest dobry pomysł, aby być ostrożnym z łańcuchów, które są badania. Rzeczywiście, powinienem był stwierdzić, że zawsze używałbym [ -n "$wtf" ] lub [ -z "$wtf" ] do testowania, czy zmienna jest ustawiona, ponieważ było to konieczne, gdy uczyłem się powłoki, raz na ćwierć wieku temu. Miałem kontratak z awatronikami Basha, że ​​nie musisz się tym martwić w Bashu - jednak myślę, że kod tutaj stanowi kontrprzykład, że tak naprawdę musisz się tym martwić.

Tak, niektóre najlepsze praktyki:

  • ująć badane zmienne w cudzysłów lub
  • (w bash), użyj [[ $wtf ]] który umie obsługiwać zmienną ekspansję.
  • Użyj testów -n lub -z, aby przetestować niepuste lub puste wartości.

Odstępstwa od reguł mogą być wyjątkowe - ale nie będzie to zbyt daleko idące ich przestrzeganie.

Rozważmy kod:

wtf="1 -eq 0" 
[ $wtf ] && echo "WTF0" 
[[ $wtf ]] && echo "WTF1" 
wtf="false" 
[ $wtf ] && echo "WTF2" 
[[ $wtf ]] && echo "WTF3" 
wtf="" 
[ $wtf ] && echo "WTF4" 
[[ $wtf ]] && echo "WTF5" 
wtf="false" 
[ "$wtf" ] && echo "WTF6" 
[[ "$wtf" ]] && echo "WTF7" 
wtf="" 
[ "$wtf" ] && echo "WTF8" 
[[ "$wtf" ]] && echo "WTF9" 

która produkuje:

WTF1 
WTF2 
WTF3 
WTF6 
WTF7 

zarówno bash i ksh (jak ustalono w MacOS X 10.6.4, gdy uruchamiane z '' lub bash testcode.sh "ksh testcode.sh"). Prawdziwa powłoka Bourne'a (jeśli nadal możesz znaleźć coś takiego) sprzeciwiłaby się operacjom z dwoma nawiasami - nie byłaby w stanie znaleźć polecenia "[[" na $PATH.

Można rozszerzyć zakres testów, aby objąć więcej przypadków ad nudności.

+0

OK, ma sens. Podświetlanie składni uczyniło mnie rzeczą, którą booleanie otrzymali. Chyba oczekiwałem za dużo. – i30817

+0

W rzeczywistości jest jeszcze dziwniej - jeśli $ wtf ma w nim spacje, zostanie ocenione jako wyrażenie. Wypróbuj go za pomocą 'wtf =" 1 eq 0 "' i 'wtf =" 1 eq 1', aby zobaczyć efekt.Aby uzyskać jeszcze więcej komedii spróbuj 'wtf =" 1 eq "' –

+0

Test 4/5 to duplikat testu 8/9 Myślę, że zamierzałeś zrobić 4/5 bez cudzysłowu wokół zmiennej (ale wynik jest taki sam - nic nie jest echo) .Również test 0/1 zmieniony przez zacytowanie zmiennej nie ocenia '1 -eq 0' więc oba typy nawiasów mają wartość true (tak jak w teście 2/3), co ciekawe, w Bash i ksh:' [''] ',' [['']] 'i' [] 'each działa i zwraca wartość false, jednak "[[]]" powoduje błąd: –

0

if [ $wtf = true ] || [ ! -f . .

+0

lub nawet "if [[$ wtf == true]] || [! -f ... " – dimba

3

Oto przydatny mały trick:

wtf=false 
if $wtf || [ ! -f filethatexists.whatever ] 

W tej postaci, zawartość zmiennej są wykonywane i zwracana wartość określa, czy test przechodzi lub nie. Zdarza się, że true i false są wbudowanymi Bashami, które zwracają odpowiednią wartość.

+1

Ta" poręczna mała sztuczka "nie jest dobrą praktyką, jeśli masz ścieżkę kodową, w której' wtf' zawiera coś innego niż "prawda" lub "fałsz", zaskakujące wyniki zachowania Pusty łańcuch? $? 'przenosi się!' rm -rf/'? Err ... –