W skrypcie bash, używając warunkowego „lub” w instrukcji „if”

127

To pytanie jest kontynuacją mojego wcześniejszego pytania . Użytkownicy tej witryny uprzejmie pomogli mi ustalić, jak napisać forpętlę bash , która będzie iterować po wartościach ciągu. Załóżmy na przykład, że zmienna sterująca pętli fnameiteruje po łańcuchach "a.txt" "b.txt" "c.txt". Chciałbym echo„tak!” kiedy fnamema wartość "a.txt"lub "c.txt"i echo„nie!” Inaczej. Próbowałem następującego skryptu powłoki bash:

#!/bin/bash

for fname in "a.txt" "b.txt" "c.txt"
do
 echo $fname
 if [ "$fname" = "a.txt" ] | [ "$fname" = "c.txt" ]; then
 echo "yes!"
else
 echo "no!"
fi
done

Otrzymuję wynik:

a.txt

Nie!

b.txt

Nie!

c.txt

tak!

Dlaczego ifstwierdzenie najwyraźniej daje wartość prawda, kiedy fnamema wartość "a.txt"? Czy użyłem |nieprawidłowo?

Andrzej
źródło
3
W skrócie ”lub„ operator to ”||” (Styl C).
Marius Cotofana,
3
Możesz również korzystać z -otego samego [ ].
Thor
6
@Thor wolałbym ||i oddzielić [ ]się -odo przenoszenia po prostu dlatego, że [nie jest gwarantowana do obsługi więcej niż 4 argumenty. Oczywiście jeśli język docelowy jest bash, nikt nie powinien być za pomocą [anyways bo bash„s [[jest lepszy pod wieloma względami.
jw013,
2
@ jw013 Dzięki. Czy to oznacza, że ​​powinienem if [[ "$fname" = "a.txt" ]] || [[ "$fname" = "c.txt" ]]raczej używać if [ "$fname" = "a.txt" ] || [ "$fname" = "c.txt" ]?
Andrew
5
@Andrew To prawda, jeśli deklarujesz shebang as bash, tak jak już to robisz. Jedną z zalet [[jest to, że nie wykonuje podziału słów (szczególny przypadek), więc [[ $unquoted_var = string ]]jest bezpieczny.
jw013,

Odpowiedzi:

225

Jeśli chcesz powiedzieć, ORużyj podwójnej rury ( ||).

if [ "$fname" = "a.txt" ] || [ "$fname" = "c.txt" ]

(Oryginalny kod OP używał |po prostu potokowania wyjścia z lewej strony do prawej strony, w taki sam sposób, jak działa zwykły potok.)

bahamat
źródło
4
Ponadto ||nie wykonuje standardowej logiki „LUB” - powoduje zwarcie, a drugie polecenie jest uruchamiane tylko w przypadku niepowodzenia pierwszego.
holdenweb,
13
@holdenweb Jestem pewien, że większość nowoczesnych zoptymalizowanych języków działa w ten sam sposób. Nie ma potrzeby poświęcania cykli procesora na ocenę drugiego warunku, ORjeśli pierwszy warunek jest prawdziwy.
bahamat
1
Myślałem, że bash się polubił, ==ale po zobaczeniu tej odpowiedzi postanowiłem to sprawdzić. Najwyraźniej „można go używać, ale nie jest standardem”. Pomyślałem, że umieszczę to tutaj dla innych, jeśli jesteś ciekawy: stackoverflow.com/a/2237103
harperville
Tak testteż poleca strona man
cdosborn
2
Możesz także użyć testu podwójnego nawiasu - if [[ "$fname" = "a.txt" ]] || [[ "$fname" = "c.txt" ]](jeśli chcesz lub musisz mieć powiązaną dodatkową funkcjonalność [[ ]]).
HankCa