якщо умова на декількох лініях в оболонці 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

3
Це заплутано, я буду радий, якщо ви можете дати пояснення щодо того, як працюють умовні висловлювання в bash ..., do_something повертає 0 після успіху, але тоді ми оновлюємо успіх до 1 ..., if ((success))оцінюється на щось інше, ніж if success. Я розгублений :)
Itay

2
@Itay ((...))- це арифметична команда. Якщо результат всередині не дорівнює нулю, він повертає істину (0). Якщо результат всередині дорівнює 0, він повертає помилку (1). "Успіх" трактується як змінна, яка, як очікується, містить число. Дивіться mywiki.wooledge.org/ArithmeticExpression
geirha

Дякую, я здогадуюсь, що частина, яка мене бентежила, полягає в тому, що 0 правда, а 1 - хибна, як правило, навпаки :)
Itay

2
@Itay Так, спочатку це може заплутатись. Bash відрізняється від мов загального призначення тим, що він "заснований на командах"; він не викликає функції, у нього немає класів і методів, він виконує команди та перевіряє статуси виходу команд. І запускати команди в bash набагато простіше, ніж такі мови, як C, python, java, perl і т. Д. Команди виходять з 0, щоб сигналізувати про успіх, і 1-255 для різних типів відмов. (Команда, як правило, може досягти успіху лише одним способом, але провалюватися з різних різних причин)
geirha

2
Це рішення має перевагу в тому, що ви можете коментувати рядки, які ви не хочете тимчасово деактивувати
Josiah Yoder

31

Використовуйте зворотні нахили.

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

EDIT

Також - я хочу переконатися, що навіть якщо перша умова справжня, всі інші умови все ще будуть оцінені.

Це неможливо лише в одному випадку, якщо заява. Натомість ви можете використовувати цикл 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
}

дякую, спробував - я отримую помилку[: do_something: unary operator expected
Itay

Ви розміщували кожну оцінку між власними дужками? Так [ expr1 ] || [ expr2 ]замість [ expr1 || expr2 ].
tectux

так, я зробив: (...
Itay

Я гадаю, що 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

\ використовується для того, щоб повідомити оболонці, що команда продовжується в наступному рядку.

EDIT : Я думаю, що це має робити те, що ви хочете:

#!/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
Itay

@Itay відповідь оновлено.
Ерік Карвальо

Оновлення питання - це ще не остаточна відповідь :(
Itay

-1

Я віддаю перевагу:

if {
    do_something "arg1" ||
    do_something "arg2" ||
    do_something "arg3"
}; then
    echo "OK"
else
    echo "NOT OK"
fi

Ваш сценарій взагалі не буде працювати: після 1-го тестового параметра він буде генерувати \nхарактер, тож ваш ifвислів створюватиме деякі помилки, а do_somethingне імена команд, тому більше помилок
damadam

Для мене це працює в zsh і bash, ЯКЩО do_somethingце функція звичайно. do_somethingповинна бути функцією або командою, що ще має бути? Більше того, я не бачу, де це призвело б до генерування \nперсонажа, окрім після повторення результату, і цього очікується ...
Toxiro
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.