Perintah terakhir yang gagal di bash

Jawaban:

6

Gunakan fcuntuk mendapatkan baris perintah sebelumnya. Ini biasanya digunakan untuk mengedit baris perintah sebelumnya di editor favorit Anda, tetapi juga memiliki mode "daftar":

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

janmoesen
sumber
ini sayangnya tidak bekerja dengan baik cukup bagaimana saya harapkan jika ada pernyataan kasus besar digunakan atau fungsi digunakan ... :( Saya akhirnya menggunakan callerdan array pesta BASH_LINENO, BASH_SOURCEdan FUNCNAMEmelakukan semacam jejak stack.
phyatt
6

Jika perintah terakhir dijalankan tanpa argumen, itu akan disimpan dalam $_variabel. Ini biasanya berisi argumen terakhir dari perintah sebelumnya - jadi jika tidak ada argumen, nilai dari $_adalah perintah terakhir itu sendiri.

Opsi lain adalah mempelajari detail perintah latar belakang terakhir . Sebagai l0b0 menulis, $!memegang PID-nya - sehingga Anda dapat mengurai output ps $!(mungkin dengan opsi format tambahan untuk ps).

rozcietrzewiacz
sumber
2

Tidak, tetapi Anda bisa mendapatkannya selama eksekusi untuk menyimpan perintah lain:

  • $0: Jalur skrip shell saat ini.
  • $FUNCNAME: "Nama fungsi saat ini."
  • "$@": Semua parameter dari perintah saat ini, dikutip secara terpisah.
  • $!: "PID (ID proses) pekerjaan terakhir yang berjalan di latar belakang."
  • $$: "ID Proses (PID) dari skrip itu sendiri."

Perintah lengkap dari skrip saat ini seharusnya "$0" "$@". Jika itu adalah fungsi seharusnya "$FUNCNAME" "$@". Anda mungkin ingin menyimpannya dalam array untuk diproses di masa mendatang. Misalnya, simpan ini di test.sh:

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

Saat berjalan ./test.sh "first argument" "second argument", itu harus kembali:

./test.sh first\ argument second\ argument

Itu adalah panggilan yang setara.

l0b0
sumber
Di bash ada BASH_COMMANDvariabel, tetapi tampaknya tidak berguna dengan cara apa pun, selain digunakan dalam perangkap.
enzotib
Terima kasih atas masukan Anda. Bagaimana jika saya menjalankan some-commandskrip shell, dan gagal. Saya akan memiliki status bukan nol $?, akankah "tidak" masih berlaku untuk keberadaan holding variabel some-command?
Eimantas
Sejauh yang saya tahu, satu-satunya fakta bahwa sebuah perintah gagal tidak mengubah set informasi yang disimpan oleh shell Anda tentang hal itu. Jadi saya akan mengatakan Ya, "tidak" .
rozcietrzewiacz
2

The DEBUGperangkap memungkinkan Anda menjalankan perintah yang tepat sebelum eksekusi perintah sederhana. Versi string dari perintah untuk mengeksekusi (dengan kata-kata dipisahkan oleh spasi) tersedia dalam BASH_COMMANDvariabel.

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

echo "last command is $previous_command"

Catatan yang previous_commandakan berubah setiap kali Anda menjalankan perintah, jadi simpan ke variabel untuk menggunakannya. Jika Anda ingin mengetahui status pengembalian perintah sebelumnya juga, simpan keduanya dalam satu perintah.

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

Jika Anda hanya ingin membatalkan perintah yang gagal, gunakan set -euntuk membuat skrip Anda keluar dari perintah pertama yang gagal. Anda dapat menampilkan perintah terakhir dari EXITperangkap .

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

Pendekatan alternatif yang mungkin bisa digunakan untuk beberapa penggunaan adalah menggunakan set -xuntuk mencetak jejak eksekusi skrip dan memeriksa beberapa baris terakhir jejak.

Gilles 'SANGAT berhenti menjadi jahat'
sumber
0

Saya merasa penting untuk menemukan perintah terakhir yang gagal ketika memiliki set -edan set -o pipefailopsi, karena jika tidak bash hanya dibatalkan tanpa umpan balik tentang mengapa, jadi ini yang saya temukan bekerja dengan baik:

#!/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"

Jika Anda menjalankan hal di atas, Anda akhirnya akan melihat semacam keluaran di bawah ini:

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

Nomor baris mungkin tidak selalu akurat, tetapi harus memberi Anda sesuatu yang cukup dekat untuk berguna.

haridsv
sumber