Як зупинити скрипт bash, коли стан не вдається?


11

Тут показано, що використовувати ||і &&в одному рядку для об'єднання виконання команд: Як я можу перевірити помилки apt-get у скрипті bash?

Я намагаюся зупинити виконання сценарію, якщо певна умова не вдається,

напр

false || echo "Obvious error because its false on left" && exit

Тут він друкує Obvious error because its false on the leftта виходить із консолі, що я хотів.

true || echo "This shouldn't print" && exit

Тут немає друку ехо, але exitкоманда також працює, тобто консоль закрита, чи не повинна exitкоманда не запускатися, оскільки команда echo праворуч не виконувалася? Або за замовчуванням оператор вважається помилковим на лівій частині &&оператора?

Редагувати: я повинен був згадати це раніше, моєю метою було повторити помилку та вийти, якщо вона не була зрозумілою. wrt до мого конкретного випадку помилок уловлювання під час групування умов за допомогою && та ||, @ bodhi.zazen відповідь вирішує проблему.

Відповідь @takatakatek робить більш зрозумілим про контроль потоку, а посилання на направляючі bash чудові

@muru відповідь має гарне пояснення, чому не використовувати set -e, якщо ви хочете, щоб користувацькі повідомлення про помилки перекидались альтернативами використання perl та trap, що, на мою думку, є більш надійним способом, і я бачу, як я використовую його з мого другого скрипту bash!


Наскільки я можу сказати, він закінчується, коли виконується сценарій.
Пантера

Відповіді:


10

Ви, мабуть, хочете (як вказував steeldriver)

true || { echo "This shouldn't print" && exit; }

Інакше ваш сценарій читає один умовний час

a або b, а потім вийти

Я думаю, ти хочеш або (b і вихід)?


4
Насправді, ви повинні використовувати { ... ; }(як @steeldriver запропонував), інакше exitєдиний виходить з нижньої частини, і батьківська оболонка продовжує виконувати сценарій.
Гордон Девіссон

14

Проблема в тому, що || і && пропускають лише одну наступну строфу командного ланцюга, коли умова не вдається. Якщо ви виписуєте повну структуру блоку, це має сенс. Те, що ви написали, стає таким:

if ! true ; then
   echo "This shouldn't print"
else
   exit
fi

Що ви хочете, це таке:

if ! true ; then
   echo "This shouldn't print"
   exit
fi

Коли ви використовуєте умовні оператори ярлика Баша, краще уникати їх змішування. Логіку зрозуміти набагато простіше, поки ви пишете її, і ваші читачі оцінять ваш гарний стиль.


2
Так, на мою думку, це набагато більше, як слід писати умову в
баші

@takatakatek Це робить більш зрозумілим, чому це не в моєму випадку. Я погоджуюся, що логіка в цьому чітка, але це не є причиною групування умов за допомогою && та || це уникати вираження їх за допомогою умовних висловлювань?
косол

@kosol Так, && та || комбінуйте дві речі: Тестування стану виходу попередньої команди та визначення однієї команди (або групи команд), яку слід виконати (для &&) або пропустити (для ||). Вони можуть бути корисні для дуже простих випадків, але не можуть замінити повністю виражені if ... then ... elif ... else ... fiблоки. Я підозрюю, що ви можете не знати, що Bash не має справжніх булевих типів, які можна побачити на більш складних мовах. Якщо статус виходу команди 0 (нуль), Bash трактує це як істинний / успішний . Якщо статус виходу не дорівнює нулю, Bash трактує це як помилковий / збій .
такакататек

7

Найпростіший спосіб відмовитися від помилки - це використовувати -eваріант bash ( set -eабо /bin/bash -eв shebang). Однак це не дозволяє легко надсилати власні повідомлення про помилки. Є кілька ідіом, які можуть спростити:

die à la Perl

Perl має дуже зручну dieкоманду, яка друкує повідомлення на stderr та створює виняток, що, як правило, призводить до завершення сценарію. Ви можете наслідувати це:

die () {
  ret=$?
  print "%s\n" "$@" >&2
  exit "$ret"
}

false || die "Obvious error because its false on left"
true || die "This shouldn't print"

trap ERR

trap <command>Команда може бути використана для виконання команди при отриманні сигналу, або при виході з сценарію ( trap ... EXIT), або коли команда повертає помилку ( trap ... ERR). Тож щось на кшталт:

trap 'ret=$?; printf "%s\n" "$ERR_MSG" >&2; exit "$ret"' ERR

Тоді:

ERR_MSG="Obvious error because its false here"
false
ERR_MSG="This shouldn't print"
true

У будь-якому випадку я б запропонував використовувати принаймні exit 1, щоб вказати, що сценарій не вдався . Звичайна exitбуде використовувати статус виходу попередньої команди, яка в цих випадках буде командою echoабо printf, яка зазвичай досягає успіху. Збереження статусу виходу з ладу команди, як я зробив тут, було б непоганим.


6

Ви можете спробувати трохи експериментувати із запуском сценарію

#!/bin/bash -e

-E гарантує, що сценарій закінчується в момент, коли щось повернеться хибним. Потім можна уникнути конкретного провалуsomething || true

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.