В bash есть ли способ сделать более короткие (если или) заявления?

if [ foo = bar -o foo = car -o foo = jar -o foo = foo ]
  then
    echo yes
fi

Чтобы держать вещи более организованными, я хотел бы попытаться сопоставить их со списком, таким как

if [ foo = {bar,car,jar,foo} ] ; then

Очевидно, что метод расширения фигурных скобок не сработал, иначе я бы не стал не быть здесь! Но я хотел бы знать, возможно ли что-то подобное вообще.

7
задан 9 May 2015 в 05:45

3 ответа

Я предлагаю использовать выбирающую структуру. Что-то как:

case $foo in
    foo|car|bar|jar) echo yes ;;
    *) ;;
esac

, Если Вам нравится, можно добавить команду между *) и ;;, чтобы быть выполненными, когда $foo не соответствует foo, car, bar, или jar. Например, Вы могли распечатать сообщение с echo 'wrong input' или что-то как этот.

0
ответ дан 9 May 2015 в 05:45

Еще короче:

[[ $foo =~ ^([bcj]ar|foo)$ ]] && echo yes

Этот путь $foo подобран против regex, или запускающегося с b, c или j сопровождаемый ar или соответствующего точно foo.

Это использует && оператор как короткое замыкание для выполнения echo yes, только если [[ $foo =~ ^([bcj]ar|foo)$ ]] выражение оценивает к истинному.

, Если это слишком компактно, чтобы быть считанными легко, можно все еще использовать полное, если конструкция, которая делает точно то же, но более читаема:

if [[ $foo =~ ^([bcj]ar|foo)$ ]]
then
    echo yes
fi
0
ответ дан 9 May 2015 в 05:45

Это похоже на ошибку в Вашем коде, но мы можем осуществить рефакторинг его вниз действительно маленький...

Если Вы действительно записали свое выражение с [ foo = bar -o foo = car -o foo = jar -o foo = foo ], затем это, возможно, было упрощено до:

echo yes

Этот тест всегда верен потому что foo = foo всегда верно, который в свою очередь является потому что литеральная строка foo всегда то же как само.

Хотя Вы разъяснили, что этот синтаксис не появился в коде, который Вы действительно использовали, я сохранил этот вводный раздел, поскольку это - частая ошибка сделать так, особенно среди новичков. Попытка проверить значение foo этот путь не работает ни в какой оболочке стиля Границы - для исследования значения переменной с [, необходимо выполнить расширение параметра с $ (см. ниже). Этот конкретный аспект проблемы не является определенным для оболочки; например, вот тест в 7 оболочках стиля Границы.

Фиксация исходного кода

Возможно, вместо этого Вы означали проверять значение foo переменная (т.е. ее содержание, а не ее имя) против тех строк. В этом случае Ваш исходный код стал бы как:

if [ "$foo" = bar -o "$foo" = car -o "$foo" = jar -o "$foo" = foo ]; then
    echo yes
fi

Это может быть сокращено немного с коротким замыканием && оператор:

[ "$foo" = bar -o "$foo" = car -o "$foo" = jar -o "$foo" = foo ] && echo yes

Но это является еще длиннее и более сложным и повторяющимся, чем Вы, вероятно, предпочитаете. Так, хождение дальше...

Более короткие Формы через Сопоставление с образцом

Можно использовать [[ встроенный оператор соответствия регулярного выражения средства:

[[ $foo =~ ^(bar|car|jar|foo)$ ]] && echo yes

При использовании case вероятно, наиболее распространенный способ, [[ с =~ :

  • та же длина как компактное использование case (см. ниже),
  • возможно более верный для логики Вашего исходного кода, в котором это использует [[, который работает во многом как проверяемое выражение.

Таким образом, Вы могли бы предпочесть это. Это - метод, который я, вероятно, использовал бы, чтобы сделать это в ударе.

Если Вы хотели сделать что-то как этот кроме использования соответствия grep вместо [[ с =~, это подобно:

grep -Eq '^(bar|car|jar|foo)$' <<< "$foo" && echo yes

Или это:

grep -Fqe{bar,car,jar,foo} <<< "$foo" && echo yes

Острота с case

Как Serg говорит, может быть упрощен с помощью case вместо if и [. Это - классик и вероятно наиболее распространенный способ.

Метод в ответе Serg работает отлично, но для конкретного кода Вы осуществляете рефакторинг, мы можем записать что-то более простое, при помощи только одного шаблона для case. Нет никакой потребности иметь вместилище *) соответствие в конце. Если строка не соответствует ни одному из шаблонов, управление просто проваливается, конструкция случая и никакие команды выполняются, который эквивалентен Вашему if создайте без else.

case $foo in bar|car|jar|foo) echo yes;; esac

Это делает это коротким и достаточно простым легко соответствовать - и быть читаемым - на одной строке (который, кажется, то, что Вы ищете). Этот метод является также портативным к оболочкам стиля Границы кроме удара.

14
ответ дан 9 May 2015 в 05:45

Другие вопросы по тегам:

Похожие вопросы: