Значення $? (знак питання долара) у скриптах оболонки


Відповіді:


212

Це статус виходу останньої виконаної команди.

Наприклад, команда trueзавжди повертає статус 0і falseзавжди повертає статус 1:

true
echo $? # echoes 0
false
echo $? # echoes 1

З посібника: (доступно, зателефонувавши man bashдо вашої оболонки)

$?       Розширюється до статусу виходу останнього виконаного переднього плану трубопроводу.

За умовою статус виходу 0означає успіх, а ненульовий стан повернення означає збій. Дізнайтеся більше про статуси виходу на wikipedia .

Існують і інші спеціальні змінні, як це, як ви бачите в цьому онлайн-посібнику: https://www.gnu.org/s/bash/manual/bash.html#Special-Parameters


Зверніть увагу $і ?є двома різними параметрами , і $?не з'являється в БАШЕЄВ (1) довідці.
Джош Хабдас

19

$?повертає значення виходу останньої виконаної команди. echo $?друкує цінність на консолі. нуль передбачає успішне виконання, тоді як ненульові значення відображаються на різні причини відмови.

Звідси при написанні сценаріїв; Я схильний використовувати наступний синтаксис

if [ $? -eq 0 ]; then
 # do something
else
 # do something else
fi

Порівняння слід проводити на рівних 0чи не рівних 0.

** Оновлення На основі коментаря: В ідеалі, ви не повинні використовувати вищезгаданий блок коду для порівняння, зверніться до коментарів та пояснення @tripleee.


15
Ні, це антипатерн. Все, що схоже, cmd; if [ $? -eq 0 ]; thenмає бути відновлено if cmd; then. Сама мета з if(і інші оператори управління потоком в оболонці), щоб виконати команду і перевірте його стан виходу.
трійчатка

if cmd;може бути не дуже читабельним є деякі умови, особливо коли cmd посилається на інший сценарій.
Саурах Аріан

1
Зараз це ще більше неправильно. [ 1 ]і [ 0 ]вони обидві; [без оператора перевіряє, чи аргумент є не порожнім рядком.
тріплей

2
Я збираюся зробити vendor/bin/drush status bootstrap | grep -q $(vendor/bin/drush php-eval 'if (function_exists("t")) echo t("Successful");') &> /dev/null;. Якби мені довелося це помістити в єдиний рядок, if [ ... ]це було б жахливо нечитабельно. Я планую зберігати вихід цього рядка до змінної, щоб я могла просто сказати if [ $drupal_installed -eq 0 ]пізніше.
третина

1
@thirdender Правильним рішенням цього є інкапсуляція складного тесту у функції оболонки.
tripleee

12

ехо $? - Дає EXIT STATUS останньо виконаної команди . Цей ВИХІДНИЙ СТАТУС, швидше за все, буде числом, при якому ZERO передбачає Успіх і будь-яке значення НЕ-ЗЕРО, що вказує на невдачу

? - Це один спеціальний параметр / змінна в bash.

$? - Це дає значення, збережене у змінній "?".

Деякі подібні спеціальні параметри в BASH - 1,2, *, # (зазвичай в команді echo сприймаються як $ 1, $ 2, $ *, $ # тощо).



5

Приклад мінімального POSIX C виходу

Щоб зрозуміти $?, спочатку слід зрозуміти концепцію стану виходу з процесу, яка визначена POSIX . У Linux:

  • коли процес викликає exitсистемний виклик, ядро ​​зберігає значення, передане системному виклику (an int), навіть після відмирання процесу.

    Система виходу виклику викликається exit()функція ANSI C, і побічно , коли ви робите returnз main.

  • процес, який викликав дочірній процес, що виходить (Bash), часто з fork+ exec, може отримати статус виходу дитини за допомогою waitсистемного виклику

Розглянемо код Bash:

$ false
$ echo $?
1

"Еквівалент" C:

false.c

#include <stdlib.h> /* exit */

int main(void) {
    exit(1);
}

bash.c

#include <unistd.h> /* execl */
#include <stdlib.h> /* fork */
#include <sys/wait.h> /* wait, WEXITSTATUS */
#include <stdio.h> /* printf */

int main(void) {
    if (fork() == 0) {
        /* Call false. */
        execl("./false", "./false", (char *)NULL);
    }
    int status;
    /* Wait for a child to finish. */
    wait(&status);
    /* Status encodes multiple fields,
     * we need WEXITSTATUS to get the exit status:
     * http://stackoverflow.com/questions/3659616/returning-exit-code-from-child
     **/
    printf("$? = %d\n", WEXITSTATUS(status));
}

Складіть і запустіть:

g++ -ggdb3 -O0 -std=c++11 -Wall -Wextra -pedantic -o bash bash.c
g++ -ggdb3 -O0 -std=c++11 -Wall -Wextra -pedantic -o false false.c
./bash

Вихід:

$? = 1

У Bash, коли ви натискаєте клавішу Enter, fork + exec + wait відбувається, як вище, і bash потім встановлює $?статус виходу з forked процесу.

Примітка. Для таких вбудованих команд echo, як процес, не потрібно породжувати, а Bash просто встановлює $?0, щоб імітувати зовнішній процес.

Стандарти та документація

POSIX 7 2.5.2 "Спеціальні параметри" http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_05_02 :

? Розширюється до десяткового статусу виходу останнього трубопроводу (див. Трубопроводи).

man bash "Спеціальні параметри":

Оболонка спеціально обробляє кілька параметрів. На ці параметри можна посилатися лише; присвоєння їм не допускається. [...]

? Розширюється до статусу виходу останнього виконаного переднього плану трубопроводу.

ANSI C і POSIX рекомендують:

  • 0 означає, що програма була успішною

  • інші значення: програма якось вийшла з ладу.

    Точне значення може вказувати на тип відмови.

    ANSI C не визначає значення жодних значень, а POSIX вказує значення, що перевищують 125: Яке значення "POSIX"?

Bash використовує статус виходу для if

У Bash ми часто використовуємо статус виходу $?неявно для управління ifоператорами, як у:

if true; then
  :
fi

де trueпрограма, яка щойно повертає 0.

Вищезазначене еквівалентно:

true
result=$?
if [ $result = 0 ]; then
  :
fi

І в:

if [ 1 = 1 ]; then
  :
fi

[це лише програма зі дивним іменем (і вбудована Bash, яка поводиться так), і 1 = 1 ]її аргументи, див. також: Різниця між одинарними та подвійними квадратними дужками в Bash



3

Дивіться посібник Bash під 3.4.2 Спеціальні параметри :

? - Розширює стан виходу останнього виконаного переднього плану трубопроводу.

Її трохи важко знайти, оскільки вона не вказана як $?(назва змінної - "просто" ?). Також, дивіться розділ стану виходу ; звичайно;

Щасливе кодування.


2

Виводить результат останньої виконаної команди Unix

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