Cara memicu kesalahan menggunakan perintah Trap

13

Saya menggunakan Ubuntu 12.04.2. Saya mencoba menggunakan perintah "trap" untuk menangkap abnormal atau kesalahan dalam skrip shell saya tetapi saya juga mencoba untuk secara manual memicu keluar "Kesalahan".

Saya telah mencoba keluar 1, tetapi tidak akan memicu sinyal "Kesalahan".

#!/bin/bash

func()
{
    exit 1
}

trap "echo hi" INT TERM ERR
func

Tidak yakin bagaimana cara secara manual memicu sinyal keluar "Kesalahan"?

badut hutan
sumber

Jawaban:

20

yang ERRperangkap tidak untuk menjalankan kode ketika shell itu sendiri keluar dengan nol non kode kesalahan, tetapi ketika perintah dijalankan oleh shell yang yang bukan merupakan bagian dari kondisi (seperti di if cmd..., atau cmd || ......) keluar dengan non-zero status keluar (kondisi yang sama seperti apa yang menyebabkan set -eshell keluar).

Jika Anda ingin menjalankan kode saat keluar dari shell dengan status keluar non-nol, Anda harus menambahkan jebakan EXITdan periksa di $?sana:

trap '[ "$?" -eq 0 ] || echo hi' EXIT

Namun perhatikan bahwa pada sinyal yang terperangkap, perangkap sinyal dan perangkap EXIT akan dijalankan, jadi Anda mungkin ingin melakukannya seperti:

unset killed_by
trap 'killed_by=INT;exit' INT
trap 'killed_by=TERM;exit' TERM
trap '
  ret=$?
  if [ -n "$killed_by" ]; then
    echo >&2 "Ouch! Killed by $killed_by"
    exit 1
  elif [ "$ret" -ne 0 ]; then
    echo >&2 "Died with error code $ret"
  fi' EXIT

Atau untuk menggunakan status keluar seperti $((signum + 128))pada sinyal:

for sig in INT TERM HUP; do
  trap "exit $((128 + $(kill -l "$sig")))" "$sig"
done
trap '
  ret=$?
  [ "$ret" -eq 0 ] || echo >&2 "Bye: $ret"' EXIT

Namun perlu dicatat bahwa keluar secara normal pada SIGINT atau SIGQUIT memiliki potensi efek samping yang mengganggu ketika proses induk Anda adalah shell seperti bashyang mengimplementasikan penanganan tunggu dan keluar secara kooperatif terhadap interupsi terminal. Jadi, Anda mungkin ingin memastikan untuk bunuh diri dengan sinyal yang sama sebagai gantinya untuk melaporkan kepada orang tua Anda bahwa Anda memang terganggu, dan bahwa itu harus mempertimbangkan untuk keluar dengan sendirinya jika menerima SIGINT / SIGQUIT.

unset killed_by
for sig in INT QUIT TERM HUP; do
  trap "exit $((128 + $(kill -l "$sig"))); killed_by=$sig" "$sig"
done
trap '
  ret=$?
  [ "$ret" -eq 0 ] || echo >&2 "Bye: $ret"
  if [ -n "$killed_by" ]; then
    trap - "$killed_by" # reset handler
    # ulimit -c 0 # possibly disable core dumps
    kill -s "$killed_by" "$$"
  else
    exec "$ret"
  fi' EXIT

Jika Anda ingin ERRjebakan terbakar, jalankan saja perintah dengan status keluar yang tidak nol seperti falseatau test.

Stéphane Chazelas
sumber
6

Gunakan kembali, tidak keluar, untuk menetapkan status pada saat keluar dari fungsi (jika fungsi jatuh-melalui tanpa kembali, status adalah bahwa dari pernyataan terakhir yang dijalankan.) Jika Anda mengganti returnuntuk exitdi contoh pertanyaan ini, ia akan bekerja sebagai Saya pikir Anda bermaksud: jebakan akan dipicu pada sinyal semu ERR dan 'hai' akan dicetak. Untuk pertimbangan tambahan, coba ini:

#!/bin/bash

func()
{
    echo 'in func'
    return 99
    echo 'still in func'
}

trap 'echo "done"' EXIT
trap 'status=$?; echo "error status is $status"; trap - EXIT; exit $status' ERR
func
echo 'returned from func'

Anda dapat mencoba berbagai modifikasi, seperti mengembalikan 0, mengomentari perangkap ERR, tidak membatalkan perangkap EXIT dalam penangan ERR, tidak keluar dari penangan ERR, atau menghapus pengembalian dan menempatkan falsesebagai pernyataan terakhir di func.

sdenham
sumber