Присвоение кода выхода локальной переменной оболочки

42
#!/bin/bash
function0()
{
 local t1=$(exit 1)
 echo $t1
}

function0

echoпечатает пустое значение Я ожидал:

1

Почему t1переменной не присваивается возвращаемое значение команды выхода - 1?

Жиль "ТАК - перестань быть злым"
источник

Ответы:

58

local t1=$(exit 1) говорит оболочке:

  • бегать exit 1в дольках;
  • сохраните свой вывод (как, например, текст, который он выводит на стандартный вывод) в переменной t1, локальной для функции.

Таким образом, это нормально, что t1заканчивается пустым.

( $()известен как подстановка команд .)

Код выхода всегда присваивается $?, так что вы можете сделать

function0()
{
  (exit 1)
  echo "$?"
}

чтобы получить эффект, который вы ищете. Конечно, вы можете назначить $?другую переменную:

function0()
{
  (exit 1)
  local t1=$?
  echo "$t1"
}
Стивен Китт
источник
1
Вы знаете, вы всегда можете положить возврат в трубу тоже. `$ (trap 'printf" :: ERRNO: $? "' 0; # теперь делайте что угодно, однако - эта ловушка будет гарантировать, что последняя записанная строка будет последним возвращением для всего контекста замещения.
mikeserv
1
@mikeserv ты пропустил обратный удар? $(trap 'printf "::ERRNO:$?"' 0; # now do whatever however
Доктор J
12

Код выхода был сохранен в $? переменная. Используя подстановку команд только для захвата вывода, вы должны использовать (...) для создания подоболочки :

#!/bin/bash

func() {
  (exit 1)
  local t1=$?
  printf '%d\n' "$t1"
}

func
cuonglm
источник
смысл задания t1=$?- использовать его, нет? и не $?будет забит заданием оп? Я думаю, что спрашиваю, не должно ли это бытьprintf '%d\n' "${t1}"
Dani_l
@Dani_l: Спасибо, это опечатка. Обновлено.
cuonglm
Обратите внимание, что подстановка команд захватывает только стандартный выход, если не перенаправлен иначе.
Phyatt
7

В bashэтом работает:

loc(){  local   "x=$(exit "$1"):$?"
        printf  '$%s:\t%d\n' \
                 x "${x##*:}" \? "$?"
}

Это связано с порядком оценки команд и назначения переменных. localимеет собственное возвращаемое значение - и это текущая команда, а не подстановка команды. Причина такие вещи, как ...

x=$(exit 1); echo "$?"

... может вернуть 1, потому что в этой команде никогда нет возврата, за исключением запуска подоболочки для присвоения $xзначения - так$? он не становится засоренным, как это происходит практически во всех других случаях, когда используются подстановки команд.

В любом случае, с localэтим действительно происходит заторможенность - но если вы поймаете его как раз в нужное время - то есть, пока расширения еще оцениваются и до того, local как у подпрограмм есть шанс засорять это - вы все равно можете назначить его.

unset x; loc 130; echo "${x-\$x is unset}"

... печать ...

$x: 130
$?: 0
$x is unset

Вы должны знать, однако, что во многих оболочках вы не можете рассчитывать на то, $?что вас поставили на среднюю оценку таким образом. На самом деле, это, вероятно, потому что эти оболочки не утруждают себя переоценкой на каждом возможном этапе, как, возможно,bash делает - что, я бы поспорил, вероятно, лучшее поведение, чем у bash. Вы действительно хотите, чтобы ваш интерпретатор рекурсивно оценивал значения цикла, которые, скорее всего, будут перезаписаны до того, как у вас появится возможность их использовать?

Во всяком случае, вот как вы можете это сделать.

mikeserv
источник
-1

В зависимости от того, почему вы пытаетесь просто получить код выхода, вы также можете просто запустить, if some-command; then echo "Success $?"; else echo "Failure $?"; fiкоторый ничего не делает с выводом команды, он просто оценивает код выхода команды run. Вы можете добавить or(or $ ( around the command and you'll still get the same results. A better example might beесли grep -q 'somestring' somefile; затем echo "Найден код выхода somestring равным $?"; Иначе "Не найден код выхода somestring равным $?"; Fi`.

Вы также можете проверить код возврата функции, который может быть явным return 3или подразумеваемым кодом возврата, который является результатом последней команды, в этом случае вам нужно быть осторожным, чтобы у вас не было echoв конце функция, в противном случае она маскирует / сбрасывает предыдущий код выхода.

command_last () {
  echo "True is `true`"
  echo "False is `false`"
  false
}
command_last; echo $?
# Outputs:
# True is 0
# False is 1
# 1

echo_last () {
  echo "True is `true`"
  echo "False is `false`"
  false
  # echo'ing literally anything (or nothing) returns true aka exit 0
  echo
}
echo_last; echo $?
# Outputs:
# True is 0
# False is 1
#            # Blank line due to empty echo
# 0

Наконец, подвох, поскольку вы не можете сделать это, VAR=(SOME_COMMAND)потому что VAR=()это определение массива, поэтому вам нужно VAR=( $(echo 'Some value') ).

dragon788
источник
Все заявленные выходные данные неверны из-за того, что подстановка команд не дает код выхода, что является целым вопросом. Непонятно, при чем тут «подвох».
Ник Маттео