Як умовно щось зробити, якщо команда вдалася чи не вдалася


Відповіді:


359

Як умовно щось зробити, якщо команда вдалася чи не вдалася

Саме це і ifробить вислів Баша:

if command ; then
    echo "Command succeeded"
else
    echo "Command failed"
fi

Додавання інформації з коментарів: у цьому випадку не потрібно використовувати синтаксис [... сама по собі команда, майже майже рівнозначна . Це, мабуть, найпоширеніша команда, яка використовується в , що може призвести до того, що вона є частиною синтаксису оболонки. Але якщо ви хочете перевірити, вдалася чи ні команда, використовуйте саму команду безпосередньо з , як показано вище.][testifif

Редагувати: Цитуйте питання вгорі для наочності (ця відповідь не відображається вгорі сторінки).


11
Зауважте, що крапка з комою є важливою.
Thorbjørn Ravn Andersen

21
Або ви можете просто поставити thenокремий рядок.
l0b0

36
@Joe: Я думаю, ти маєш на увазі if ! command ; then ... ; fi. [сама по собі команда, і вона не потрібна в цьому випадку.
Кіт Томпсон

20
@Joe: Мій шлях також має честь бути правильним. if [ ! command ]не виконується command; він трактує commandяк рядок і трактує його як істинне, оскільки має ненульову довжину. [є синонімом testкоманди
Кіт Томпсон

5
На жаль Ви маєте рацію.
Джо

133

Для дрібних речей, які ви хочете статися, якщо працює команда оболонки, ви можете використовувати &&конструкцію:

rm -rf somedir && trace_output "Removed the directory"

Аналогічно для дрібних речей, які ви хочете статися, коли команда оболонки не працює, ви можете використовувати ||:

rm -rf somedir || exit_on_error "Failed to remove the directory"

Або і те й інше

rm -rf somedir && trace_output "Removed the directory" || exit_on_error "Failed to remove the directory"

Мабуть, нерозумно робити це з цими конструкціями, але вони можуть іноді зробити потік управління набагато чіткішим.


3
Вони коротші і (принаймні в деяких оболонках) швидші. Я здригаюся, згадуючи сценарій встановлення монстра Ultrix, написаний саме цими умовними конструкціями, які я одного разу намагався розшифрувати ...
vonbrand

101

Перевірте значення $?, яке містить результат виконання останньої команди / функції:

#!/bin/bash

echo "this will work"
RESULT=$?
if [ $RESULT -eq 0 ]; then
  echo success
else
  echo failed
fi

if [ $RESULT == 0 ]; then
  echo success 2
else
  echo failed 2
fi

11
Незважаючи на технічну коректність (і, таким чином, не вимагаючи протистояння), він не використовує ifідіому Баша . Я вважаю за краще відповідь Кіта Томпсона.
janmoesen

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

2
Що таке "Баш, якщо ідіома"?
Nowaker

3
@Nowaker Те, що єдиною метою ifє зробити це. Умови контролю потоку в Bash усі досліджують $?за кадром; ось що вони роблять. Явне вивчення його вартості має бути непотрібним у переважній більшості випадків і, як правило, є початківцем антипаттером.
трійчанка

1
@lunakid Якщо ви не переймаєтесь кодом виходу, if ! cmdце добре. В іншому випадку загальною умовою є використання elseпункту. Ви не можете мати порожнє, thenале іноді ви бачите, then : nothing; elseде :но-оп є важливим. trueпрацювали б і там.
трійчатка

47

Це працювало для мене:

command && echo "OK" || echo "NOK"

якщо це commandдосягає успіху, він echo "OK"виконується, і оскільки він успішний, виконання припиняється на цьому. В іншому випадку &&пропускається і echo "NOK"виконується.


5
Якщо ви хочете щось зробити, якщо це не вдалося, і зберегти вихідний код (показати в командному рядку або перевірити сценарій), ви можете зробити це: command && echo "OK" || c=$?; echo "NOK"; $(exit $c)
Сем Хаслер

2
@ Сем-Хаслер: чи не повинно бути це command && echo "OK" || (c=$?; echo "NOK"; (exit $c))?
jrw32982

9
Крім того, якщо echo "OK"частина може сама вийти з ладу, тоді це краще:command && (echo "OK"; exit 0) || (c=$?; echo "NOK"; (exit $c))
jrw32982

@ jrw32982, Ніцца, я використовував колишню конструкцію, але не останню.
Сем Хаслер

Справжня відповідь - у коментарях, дякую всім!
Джошуа Пінтер

6

Слід зазначити, що if...then...fiта &&/ ||тип підходу стосується статусу виходу, повернутого командою, яку ми хочемо перевірити (0 на успіх); однак деякі команди не повертають ненульового статусу виходу, якщо команда не вдалася або не змогла мати справу з введенням. Це означає, що звичайні ifта &&/ ||підходи не працюватимуть для цих конкретних команд.

Наприклад, в Linux GNU fileвсе ще залишається з 0, якщо він отримав як аргумент неіснуючий файл і findне зміг знайти вказаного користувачем файлу.

$ find . -name "not_existing_file"                                          
$ echo $?
0
$ file ./not_existing_file                                                  
./not_existing_file: cannot open `./not_existing_file' (No such file or directory)
$ echo $?
0

У таких випадках одним із можливих способів вирішити ситуацію є читання stderr/ stdinповідомлення, наприклад, ті, що повернулися fileкомандою, або розбір результатів команди, як в find. Для цього caseможна використовувати оператор.

$ file ./doesntexist  | while IFS= read -r output; do                                                                                                                  
> case "$output" in 
> *"No such file or directory"*) printf "%s\n" "This will show up if failed";;
> *) printf "%s\n" "This will show up if succeeded" ;;
> esac
> done
This will show up if failed

$ find . -name "doesn'texist" | if ! read IFS= out; then echo "File not found"; fi                                                                                     
File not found

2

Найбільш схильна до помилок я могла прийти:

  • По-перше, отримайте значення. Припустимо, ви робите щось на кшталт:

RR=$?

Тепер, не тільки для цієї ситуації, але й для інших, з якими ви можете зіткнутися, врахуйте:

визначена змінна:

$ AA=1 ; if (( "10#0${AA}" == 1 )) ; then echo yes ; else echo no ; fi

Відповідь: так

$ AA=1 ; if (( "10#0${AA}" != 1 )) ; then echo yes ; else echo no ; fi

Відповідь: ні

невизначена змінна:

$ AA=1 ; if (( "10#0${BB}" == 1 )) ; then echo yes ; else echo no ; fi

Відповідь: ні

$ AA=1 ; if (( "10#0${BB}" != 1 )) ; then echo yes ; else echo no ; fi

Відповідь: так

$ AA=1 ; if (( "10#0${BB}" == 0 )) ; then echo yes ; else echo no ; fi

Відповідь: так

Це запобігає помилкам від усіх видів.

Ви, напевно, знаєте про всі синтаксиси, але ось кілька порад:

  • Використовуйте цитати. Уникайте "blank"бути nothing.
  • Нове сучасне позначення змінних - це ${variable}.
  • Додавання нульового об'єднаного рівня перед вашим номером також уникає "взагалі немає номера".
  • Але зачекайте, додавання нуля змушує число стати base-8. Ви отримаєте помилку типу:
    • value too great for base (error token is "08")для номерів вище 7. Це коли 10#вступає в гру:
    • 10#змушує число бути base-10.

1

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

if ($( ping 4.4.4.4 -c1 > /dev/null )) ; then
  echo "ping response succsess!!!"
fi

9
Це працює, але суперечить. Ви запускаєте ping у підшлубку підпакеті, вихід у pingфіксований з огляду на запуск його як команди. Але тому, що висновок буде переспрямовано на / dev / null, це завжди буде порожнім рядком. Таким чином, ви нічого не запускаєте в підзарядку, що означає, що попередній статус виходу (підзаголовок підстановки команди, тобто ping) буде збережено. Очевидно, тут правильний шлях if ping ...; then.
Стефан Шазелас

1

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

Цей приклад використовується ifдля перевірки наявності файлу та чи є звичайним файлом. Якщо ці умови істинні, перевірте, чи має його розмір більше 0.

#!/bin/bash

echo "Which error log are you checking today? "
read answer

if [ -f /opt/logs/$answer*.errors ]
    then
        if [ -s /opt/logs/$answer*.errors ]
            then
                echo "Content is present in the $answer error log file."
            else
                echo "No errors are present in the $answer error log file."
        fi
    else
        echo "$answer does not have an error log at this time."
fi

2
Це те, що робить ваша відповідь, але ваша відповідь не відповідає на питання.
Джефф Шаллер

@JeffSchaller, дякую за записку. Я відредагував своє повідомлення, щоб включити посилання на питання.
кварцинкуарц

1
#!/bin/bash

if command-1 ; then
   echo "command-1 succeeded and now running from this block command-2"
   command-2
else
   echo "command-1 failed and now running from this block command-3"
   command-3
fi

3
Це зовсім схоже на існуючу прийняту відповідь ; будь ласка, припишіть роботу, яку ви повторно використовуєте, або додайте власні зусилля у відповіді.
Jeff Schaller

-3

Це можна зробити просто таким чином, оскільки $?надає статус останньої виконаної команди.

Так могло бути

#!/bin/sh

... some command ...

if [ $? == 0 ] ; then
  echo '<the output message you want to display>'
else 
  echo '<failure message>'
fi

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