условие if на нескольких строках в оболочке bash

19

У меня есть функция оболочки bash, которая принимает аргумент и выполняет что-то на нем, если это необходимо.

do_somthing() {
  if [need to do something on $1]
  then
    do it
    return 0
  else
    return 1
  fi
}

Я хочу вызвать этот метод с несколькими аргументами и проверить, удалось ли хотя бы одному из них.

Я попробовал что-то вроде:

if [ do_something "arg1" ||
     do_something "arg2" ||
     do_something "arg3" ]
then
  echo "OK"
else
  echo "NOT OK"
fi

Какой будет правильный синтаксис для этого?
РЕДАКТИРОВАТЬ
Также - я хочу убедиться, что даже если первое условие истинно, все остальные условия все равно будут оценены.

Благодарность,

Итай
источник
Я обновил свой ответ.
tectux
Спасибо, не могли бы вы привести пример?
Итай
1
Я добавил пример кода в свой ответ.
tectux

Ответы:

7

Сначала запустите команды, а затем проверьте, успешно ли хотя бы одна из них.

#!/bin/bash

success=0
do_something arg1 && success=1
do_something arg2 && success=1
do_something arg3 && success=1

if ((success)); then
    printf 'Success! At least one of the three commands succeeded\n'
fi
geirha
источник
3
Это сбивает с толку, я был бы рад, если бы вы могли дать некоторые объяснения о том, как условные операторы работают в bash ..., do_something возвращает 0 в случае успеха, но затем мы обновляем success до 1 ..., if ((success))оценивая что-то иное, чем if success. Я в замешательстве :)
Итай
2
@Itay ((...))- это арифметическая команда. Если результат внутри не равен нулю, он возвращает true (0). Если результат внутри равен 0, он возвращает false (1). «успех» рассматривается как переменная, которая, как ожидается, будет содержать число. См. Mywiki.wooledge.org/ArithmeticExpression
гейра
Спасибо, я думаю, что меня смутило то, что 0 - это истина, а 1 - ложь, обычно это наоборот :)
Итай
2
@Itay Да, сначала это может сбить с толку. Bash отличается от языков общего назначения тем, что он «основан на командах»; он не вызывает функции, у него нет классов и методов, он запускает команды и проверяет статусы выхода команд. И гораздо проще запускать команды в bash, чем в таких языках, как C, python, java, perl и т. Д. Команды выходят с 0, чтобы обозначить успех, и с 1-255 для различных типов сбоев. (Команда обычно может быть успешной только в одном случае, но не по разным причинам)
гейра
2
Преимущество этого решения в том, что вы можете закомментировать строки, которые вы не хотите временно деактивировать
Josiah Yoder
31

Используйте обратную косую черту.

if [ $(do_something "arg1") ] || \
   [ $(do_something "arg2") ] || \
   [ $(do_something "arg3") ]
then
  echo "OK"
else
  echo "NOT OK"
fi

РЕДАКТИРОВАТЬ

Кроме того - я хочу убедиться, что даже если первое условие истинно, все остальные условия все равно будут оценены.

Это невозможно только в одном условии if. Вместо этого вы можете использовать цикл for, который перебирает аргументы и оценивает их отдельно. Что-то вроде:

do_something() {
  for x in "$@"
  do
    if [need to do something on $x]
    then
      do it
    else
      echo "no action required on $x"
    fi
  done
}
tectux
источник
спасибо, попробовал - получаю ошибку[: do_something: unary operator expected
Итай
Вы ставили каждую оценку в свои скобки? Так что [ expr1 ] || [ expr2 ]вместо [ expr1 || expr2 ].
tectux
да, я сделал: (...
Итай
Я предполагаю, что do_something "arg1"это интерпретируется как два аргумента, тогда как выражение должно быть одинарным. Любой способ заставить do_something "arg1"быть оценен как один аргумент?
Итай
1
Ты прав. Это тоже работает: if [ $(do_something "arg1") ].
tectux
5

Правильный синтаксис:

if  do_something "arg1" || \
    do_something "arg2" || \
    do_something "arg3"
then
  echo "OK"
else
  echo "NOT OK"
fi

\ используется, чтобы сообщить оболочке, что команда продолжается на следующей строке.

РЕДАКТИРОВАТЬ : Я думаю, что это должно делать то, что вы хотите:

#!/bin/bash

do_something() {
  if [need to do something on $1]
  then
    do it
    echo "OK"
  else
    echo "NOT OK"
  fi
}

do_something "arg1"
do_something "arg2"
do_something "arg3"
Эрик Карвалью
источник
Спасибо, результаты с ошибкой:[: too many arguments
Итай
@ Итай Ответ обновлен.
Эрик Карвалью
Обновление вопроса - это еще не окончательный ответ :(
Итай
-1

Я предпочитаю:

if {
    do_something "arg1" ||
    do_something "arg2" ||
    do_something "arg3"
}; then
    echo "OK"
else
    echo "NOT OK"
fi
Toxiro
источник
\nВаш сценарий не будет работать вообще: после 1-го тестового параметра он сгенерирует символ, поэтому ваш ifоператор вызовет некоторые ошибки, а do_somethingне имена команд, поэтому больше ошибок
damadam
Для меня это работает в Zsh и Bash, если do_somethingэто функция, конечно. do_somethingдолжна быть функция или команда, что еще должно быть? Кроме того, я не вижу, где он будет генерировать \nперсонажа, кроме как после повторения результата, и это ожидается ...
Toxiro