Що еквівалентно && під час написання баш-сценарію?


31

Прошу вибачення заздалегідь, якщо це питання, що повторюється. Я доклав зусиль для пошуку / перевірки, перш ніж запитати тут.

Мені подобається писати однолінійки так:

foocommand && foocommand2 && foocommand3

Ідея полягала в тому, що я хочу запускати наступні команди лише у тому випадку, якщо попередня була "успішною".

Я пишу дещо тривалий сценарій, і цей одноклапник не здійснен, бо він схожий на величезний блок заплутаного коду для всіх інших.

Я хочу виділити команди та написати коментарі між ними в сценарії. Як я можу це зробити, і все ще є еквівалент && там?


4
Це ведмеді повторити: &&не означає , що подальша команда буде працювати , якщо попередній один був успішним. Це означає , що команда буде працювати , якщо колективний результат з усіх попередніх команд в списку команд успіху. Ви можете це знати, але майбутні читачі можуть неправильно зрозуміти.
kojiro

1
Крім того, як примітка, така поведінка, яку ви описуєте, походить від ||і &&(на відміну від |або &) називається коротким замиканням. Поведінка, що використовується з останніми операторами, називається прагненням до оцінки.
AndyPerfect

7
@kojiro: Я не бачу різниці. a && b && cзапускається лише в тому bвипадку, коли це aвдасться, тому "він працює лише у cвипадку bуспіху" і "він працює лише у тому cвипадку, якщо aі те й bінше досягає успіху" є рівнозначними твердженнями: bне можна досягти успіху, якщо не aвдалося.
ruakh

1
@ruakh a || b && cє більш показовим.
kojiro

8
@ruakh ні, true || false && echo hiвийде hi. Технічна специфікація гласить: Оператори "&&" та "||" має рівний пріоритет і оцінюється лівою асоціативністю.
kojiro

Відповіді:


23

Ви можете це зробити так:

#!/bin/sh
ls -lh &&
    # This is a comment
    echo 'Wicked, it works!'

Сподіваюся, я зрозумів, що ви правильно запитали.


Спасибі. Це найближче до того, що я сподівався зробити. І це дуже легко перетворити назад в один вкладиш, якщо це необхідно.
Майк Б

Майк, оскільки ви стурбовані чистотою коду, загальною умовою є відступ 2-N ділянок ланцюга під першим.
jblaine

@jblaine Я не впевнений, що я розумію, що ти маєш на увазі. Чи можете ви, будь ласка, докладно?
Майк Б

Майк, Stackexchange не дасть мені правильно відформатувати свою відповідь, тому ось усе, що я мав на увазі: відступ
jblaine

@jblaine Добрий пункт, відредагований для відступу рядків.
Volker Siegel

38

Ви можете змінити лінію shebang на

#!/bin/bash -e

Після будь-якої помилки сценарій зупиниться.


1
Цікаво. Я буду пам'ятати про це Дякую.
Майк Б

рятує мене від набору тексту -е, коли мені це потрібно
Silverrocker

@Silverrocker Це теж POSIX (за винятком bashчастини курсу). Оболонка POSIX займає купу опцій, застосовних до set. Або навпаки? setце спосіб встановлення параметрів командного рядка оболонки в сценарії.
Каз

7
На жаль, існує ряд стандартних утиліт, які не дотримуються звичайних угод про статус виходу, тому -eможуть неправильно поводитися. Наприклад, ви, мабуть, не хочете, щоб ваш сценарій припинявся щоразу, коли ви diffдва невідповідні файли. Ви, звичайно, можете обійти це, додавши || true(або, можливо || [ $? = 1 ]) до таких команд, але ОП згадує "всіх інших", хто повинен буде прочитати цей сценарій, і сказав, що "всі інші", ймовірно, не звикли до того, щоб впоратися -e.
ruakh

4
Я звик ставити -eна she-bang, поки один адміністратор моєї компанії не продовжував запускати мої сценарії bash myscript.sh, тому він ігнорував це -e. Тепер у всіх моїх сценаріях є а set -eу другому рядку.
Карлос Кампдеррос

19

Якщо set -eідея вам не подобається , можливо, ви можете перетворити логіку.

foocommand || exit 1
foocommand2 || exit 2
foocommand3 || exit 3

Більш корисно замінити exitчимось, щоб надрукувати корисне повідомлення про помилку, а потім вийти. Всередині функції, звичайно, ви хочете returnзамість цього exit.


11
Або foocommand || exitвийти зі foocommandстатусом 's вихід, якщо він не дорівнює нулю.
Стефан Шазелас

Як це працює? Це як у C - якщо лівий аргумент оцінює TRUE, не перевіряється більше аргументів?
Vorac

Так, правильно. Це звичайна ідіома в Ліспі (і функціональних мовах загалом, я думаю) і в Perl.
трійка

9

Ви можете використовувати if else fiблоки замість цього.

if foocommand; then

  # some comments

  if foocommand2; then

    # more comments

    foocommand3
  fi
fi

Це трохи читабельніше.

Крім того, ви можете просто використовувати, \щоб розбити великий 1 вкладиш на кілька ліній

foocommand && \
  # some comment
  foocommand2 && \
    # more comment
    foocommand3

Але, звичайно, це може заплутати нетренований очей.


4
Я не думаю, що \необхідне там.
Samuel Edwin Ward

Ти правий. Сила звички.
Мартін Канавал

5

Можна розглянути можливість використання вкладених ifоператорів. Інший варіант - використовувати фігурні для групування, як{ true && echo hi; } || echo huh

Оновлення 1:

Ось приклад без нових рядків / коментарів:

{ { false && echo "inner true"; } && { echo "inner true" && true; } || { echo "inner false" && false; } || echo "outter false"; }

@Stephane Дякую за додавання крапки з комою. Я використовую свій телефон, щоб відповісти, тому не перевіряв свої відповіді. :)
livingstaccato

Цікава ідея. Так, я думав про вкладені у висловлювання, але якщо я прив'язую багато речей разом, це може заплутатися.
Майк Б

4

Розбийте кожну послідовність команд на функції:

big_block_1() {
  # ...
}
big_block_2() {
  # ...
}
big_block_3() {
  # ...
}

big_block_1 && big_block_2 && big_block_3

0

Мені завжди подобається писати функцію "провал", яка дозволяє мені вказати те, що я збирався зробити, коли стався збій, а потім використовувати ||шаблон. Як і наступне:

function fail() {
  echo "Failure: ${@}"
  exit 1
}

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