В скрипте bash, используя условное «или» в выражении «если»

129

Этот вопрос является своего рода продолжением моего предыдущего вопроса . Пользователи на этом сайте любезно помогли мне определить, как написать forцикл bash, который перебирает строковые значения. Например, предположим, что переменная управления цикла fnameперебирает строки "a.txt" "b.txt" "c.txt". Я хотел бы echo"да!" когда fnameимеет значение "a.txt"или "c.txt", и echo"нет!" в противном случае. Я пробовал следующий скрипт оболочки 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

Я получаю вывод:

a.txt

нет!

b.txt

нет!

c.txt

да!

Почему ifутверждение очевидно дает истину, когда fnameимеет значение "a.txt"? Я |неправильно использовал ?

Андрей
источник
3
В bash оператор 'или' равен '||' (Стиль С).
Мариус Котофана
3
Вы также можете использовать -oв том же [ ].
Тор
6
@Thor я предпочел бы ||и отдельно [ ]над -oпортативность просто потому , что [не гарантирует поддержку более чем 4 аргумента. Конечно , если целевой язык bash, никто не должен использовать в [любом случае , потому что bash«s [[превосходит во многих отношениях.
jw013
2
@ jw013 Спасибо. Означает ли это, что я должен использовать, if [[ "$fname" = "a.txt" ]] || [[ "$fname" = "c.txt" ]]а не if [ "$fname" = "a.txt" ] || [ "$fname" = "c.txt" ]?
Андрей
5
@ Андрей Это правильно, если вы объявляете Шебанг как bash, как вы уже делаете. Одним из преимуществ [[является то, что он не выполняет разбиение слов (особый случай), поэтому [[ $unquoted_var = string ]]является безопасным.
jw013

Ответы:

229

Если вы хотите сказать, ORиспользуйте двойную трубу ( ||).

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

(Исходный код OP, использующийся, |просто передавал выходные данные с левой стороны на правую сторону, точно так же, как любая обычная труба работает.)

bahamat
источник
4
Кроме того, ||не выполняет стандартную логику «ИЛИ» - она ​​замыкает накоротко, а вторая команда запускается только в случае сбоя первой.
holdenweb
13
@holdenweb Я уверен, что большинство современных оптимизированных языков работают одинаково. Нет необходимости тратить циклы ЦП на оценку второго условия, ORесли первое условие оценивается как истинное.
Багамат
1
Я думал, что Bash понравилось, ==но увидев этот ответ, я решил посмотреть его. Видимо, «это можно использовать, но не стандартно». Я подумал, что
выложу
Это то, что руководство testman рекомендует тоже
cdosborn
2
Вы также можете использовать двойные скобки - if [[ "$fname" = "a.txt" ]] || [[ "$fname" = "c.txt" ]](если вы хотите или должны иметь дополнительную функциональность, связанную с [[ ]]).
HankCa