Risposte:
Utilizzare fc
per ottenere la riga di comando precedente. Viene normalmente utilizzato per modificare la precedente riga di comando nel tuo editor preferito, ma ha anche una modalità "elenco":
last_command="$(fc -nl -1)"
caller
e gli array bash BASH_LINENO
, BASH_SOURCE
e FUNCNAME
di fare una sorta di traccia dello stack.
Se l'ultimo comando è stato eseguito senza argomenti, verrà salvato nella $_
variabile. Normalmente contiene l' ultimo argomento del comando precedente, quindi se non c'erano argomenti, il valore di $_
è l'ultimo comando stesso.
Un'altra opzione è imparare i dettagli dell'ultimo comando in background . Come ha scritto l0b0, $!
contiene il suo PID, in modo da poter analizzare l'output di ps $!
(possibilmente con opzioni di formattazione aggiuntive su ps
).
No, ma è possibile ottenerlo durante l'esecuzione per memorizzare altri comandi:
$0
: Percorso dello script di shell corrente.$FUNCNAME
: "Nome della funzione corrente.""$@"
: Tutti i parametri del comando corrente, indicati separatamente.$!
: "PID (ID processo) dell'ultimo lavoro eseguito in background."$$
: "Process ID (PID) dello script stesso."Dovrebbe quindi essere il comando completo dello script corrente "$0" "$@"
. Se è una funzione dovrebbe essere "$FUNCNAME" "$@"
. Si consiglia di archiviarlo in un array per elaborazioni future. Ad esempio, memorizzalo in test.sh
:
#!/usr/bin/env bash
foo()
{
declare -a command=("$0")
for param in "$@"
do
command+=("$(printf %q "$param")")
done
echo "${command[@]}"
}
foo "$@"
Durante l'esecuzione ./test.sh "first argument" "second argument"
, dovrebbe restituire:
./test.sh first\ argument second\ argument
Quali sono chiamate equivalenti.
BASH_COMMAND
variabile, ma non sembra essere utile in alcun modo, a parte l'uso nelle trappole.
some-command
in uno script di shell, e non riesce. Avrò uno stato diverso da zero $?
, "no" rimarrà valido per l'esistenza di un mantenimento variabile some-command
?
La DEBUG
trap consente di eseguire un comando subito prima di qualsiasi semplice esecuzione del comando. Nella BASH_COMMAND
variabile è disponibile una versione stringa del comando da eseguire (con parole separate da spazi) .
trap 'previous_command=$this_command; this_command=$BASH_COMMAND' DEBUG
…
echo "last command is $previous_command"
Nota che previous_command
cambierà ogni volta che esegui un comando, quindi salvalo in una variabile per usarlo. Se vuoi conoscere anche lo stato di ritorno del comando precedente, salva entrambi in un unico comando.
cmd=$previous_command ret=$?
if [ $ret -ne 0 ]; then echo "$cmd failed with error code $ret"; fi
Se si desidera interrompere solo comandi non riusciti, utilizzare set -e
per far uscire lo script dal primo comando non riuscito. È possibile visualizzare l'ultimo comando dalla EXIT
trap .
set -e
trap 'echo "exit $? due to $previous_command"' EXIT
Un approccio alternativo che potrebbe funzionare per alcuni usi è quello set -x
di stampare una traccia dell'esecuzione dello script ed esaminare le ultime righe della traccia.
Trovo essenziale trovare l'ultimo comando fallito quando si hanno set -e
e le set -o pipefail
opzioni, altrimenti Bash si interrompe semplicemente senza feedback sul perché, quindi questo è quello che ho trovato funzionante:
#!/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"
Se esegui quanto sopra, finirai per vedere il seguente tipo di output:
The following command causes bash to abort, but it should also result in a nice message
ERROR: Aborting at line: 22 on command: false
Il numero di riga potrebbe non essere sempre preciso, ma dovrebbe darti qualcosa di abbastanza vicino per essere utile.