Последняя неудачная команда в bash

9

$?Переменная имеет статус выхода последней команды запуска. Существует ли переменная, которая содержит последнюю команду запуска?

Eimantas
источник
Связанный вопрос о переполнении стека: BASH: повторение последнего запуска команды
Жиль "ТАК - перестань быть злым"

Ответы:

6

Используйте fcдля получения предыдущей командной строки. Обычно он используется для редактирования предыдущей командной строки в вашем любимом редакторе, но также имеет режим «списка»:

last_command="$(fc -nl -1)"

janmoesen
источник
это , к сожалению , не работает совсем , как я ожидал , если есть большие заявления в случае использования или функций в использовании ... :( Я закончил с использованием callerи Баш массивы BASH_LINENO, BASH_SOURCEи FUNCNAMEделать вид трассировки стека.
phyatt
6

Если последняя команда была выполнена без аргументов, она будет сохранена в $_переменной. Обычно он содержит последний аргумент предыдущей команды - поэтому, если аргументов не было, значением $_является сама последняя команда.

Другой вариант - узнать подробности последней фоновой команды. Как писал l0b0, $!содержит его PID - так что вы можете анализировать вывод ps $!(возможно, с дополнительными опциями форматирования ps).

rozcietrzewiacz
источник
2

Нет, но вы можете получить его во время выполнения, чтобы сохранить для других команд:

  • $0Путь текущего сценария оболочки.
  • $FUNCNAME: "Имя текущей функции."
  • "$@": Все параметры текущей команды, указаны отдельно.
  • $!: "PID (идентификатор процесса) последнего запуска задания в фоновом режиме."
  • $$: "Идентификатор процесса (PID) самого скрипта."

Поэтому полная команда текущего скрипта должна быть "$0" "$@". Если это функция, то так и должно быть "$FUNCNAME" "$@". Возможно, вы захотите сохранить это в массиве для дальнейшей обработки. Например, сохраните это в test.sh:

#!/usr/bin/env bash
foo()
{
    declare -a command=("$0")
    for param in "$@"
    do
        command+=("$(printf %q "$param")")
    done
    echo "${command[@]}"
}
foo "$@"

При запуске ./test.sh "first argument" "second argument"он должен вернуть:

./test.sh first\ argument second\ argument

Какие эквивалентные звонки.

l0b0
источник
В bash есть BASH_COMMANDпеременная, но она, кажется, не пригодится ни в коем случае, кроме использования в ловушках.
энзотиб
Спасибо за ваш вклад. Что делать, если я запускаю some-commandсценарий оболочки, и он терпит неудачу. У меня будет ненулевой статус $?, будет ли "нет" все еще сохраняться для существования переменной хранения some-command?
Eimantas
Насколько я знаю, единственный факт, что команда не выполнена, не меняет набор информации, хранящейся в вашей оболочке. Так что я бы сказал, да, нет .
rozcietrzewiacz
2

DEBUGЛовушка позволяет выполнить команду прямо перед любым простым выполнением команды. Строковая версия команды для выполнения (со словами, разделенными пробелами) доступна в BASH_COMMANDпеременной.

trap 'previous_command=$this_command; this_command=$BASH_COMMAND' DEBUG

echo "last command is $previous_command"

Обратите внимание, что это previous_commandбудет меняться при каждом запуске команды, поэтому сохраните ее в переменной, чтобы использовать ее. Если вы также хотите узнать статус возврата предыдущей команды, сохраните обе в одной команде.

cmd=$previous_command ret=$?
if [ $ret -ne 0 ]; then echo "$cmd failed with error code $ret"; fi

Если вы хотите отменить только неудачные команды, используйте, set -eчтобы ваш скрипт завершился с первой неудачной командой. Вы можете отобразить последнюю команду из EXITловушки .

set -e
trap 'echo "exit $? due to $previous_command"' EXIT

Альтернативный подход, который может работать для некоторых целей, заключается в том, set -xчтобы распечатать трассировку выполнения скрипта и изучить последние несколько строк трассировки.

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

Я считаю необходимым найти последнюю неудачную команду при наличии set -eи set -o pipefailопций, так как в противном случае bash просто прерывается без обратной связи о причине, поэтому я нашел, что это работает хорошо:

#!/usr/bin/env bash
set -eu
set -o pipefail

cur_command=
first_err_command=
first_err_lineno=
# This trap is executed in exactly the same conditions in which the `set -e` results in an exit.
trap 'cur_command=$BASH_COMMAND;
      if [[ -z "$first_err_command" ]]; then
          first_err_command=$cur_command;
          first_err_lineno=$LINENO;
      fi' ERR
trap 'if [[ ! -z "$first_err_command" ]]; then
          echo "ERROR: Aborting at line: $first_err_lineno on command: $first_err_command";
      fi' EXIT

echo "The following command causes bash to abort, but it should also result in a nice message"
false
echo "This message is not expected"

Если вы запустите вышеприведенное, вы увидите вывод ниже:

The following command causes bash to abort, but it should also result in a nice message
ERROR: Aborting at line: 22 on command: false

Номер строки не всегда может быть точным, но он должен дать вам что-то достаточно близкое, чтобы быть полезным.

haridsv
источник