Bagaimana cara menonaktifkan set -e untuk perintah individual?

36

Perintah set -e membuat skrip bash gagal segera ketika perintah apa pun mengembalikan kode keluar non-nol.

  1. Apakah ada cara yang mudah dan elegan untuk menonaktifkan perilaku ini untuk perintah individu dalam skrip?

  2. Di tempat mana fungsi ini didokumentasikan dalam Manual Referensi Bash ( http://www.gnu.org/software/bash/manual/bashref.html )?

Gustave
sumber

Jawaban:

29
  1. Sesuatu seperti ini:

    #!/usr/bin/env bash
    
    set -e
    echo hi
    
    # disable exitting on error temporarily
    set +e
    aoeuidhtn
    echo next line
    
    # bring it back
    set -e
    ao
    
    echo next line

    Menjalankan:

    $ ./test.sh
    hi
    ./test.sh: line 7: aoeuidhtn: command not found
    next line
    ./test.sh: line 11: ao: command not found
  2. Ini dijelaskan dalam setbantuan builtin:

    $ type set
    set is a shell builtin
    $ help set
    (...)
    Using + rather than - causes these flags to be turned off.

Hal yang sama didokumentasikan di sini: https://www.gnu.org/software/bash/manual/bashref.html#The-Set-Builtin .

Arkadiusz Drabczyk
sumber
Terima kasih! Saya menemukan kemungkinan lain: #! / Bin / bash set -e # Hapus komentar baris berikutnya untuk melihat efek set -e: #blubb if blubb; lalu gema, "Perintah blubb berhasil." else echo "Command blubb gagal. Kode keluar: $?" fi echo keluar script normal
Gustave
22

Alternatif untuk tidak menaati jaminan atas kesalahan adalah dengan memaksakan kesuksesan tidak peduli apa pun. Anda dapat melakukan sesuatu seperti ini:

cmd_to_run || true

Itu akan mengembalikan 0 (benar), jadi set -e tidak boleh dipicu

ernie
sumber
3
faulty_cmd || :adalah ungkapan populer lain untuk ini. (Ini :adalah perintah yang identik dengan true).
ulidtko
3
@ulidtko - menarik. Bawalah saya ke lubang kelinci untuk menemukan stackoverflow.com/questions/3224878/… ini untuk mendapatkan sejarah yang sebenarnya vs.:
ernie
12

Jika Anda mencoba menangkap kode pengembalian / kesalahan (fungsi atau garpu), ini berfungsi:

function xyz {
    return 2
}

xyz && RC=$? || RC=$?
h0tw1r3
sumber
8

Jika "keluar segera opsi shell" berlaku atau diabaikan tergantung pada konteks perintah yang dieksekusi (lihat bagian Bash Reference Manual pada Set Builtin - terima kasih kepada Arkadiusz Drabczyk).

Terutama, opsi diabaikan jika perintah adalah bagian dari tes dalam pernyataan if. Oleh karena itu adalah mungkin untuk menjalankan perintah dan memeriksa keberhasilan atau kegagalannya dalam "keluar segera konteks" menggunakan pernyataan if seperti ini:

#!/bin/bash

set -e

# Uncomment next line to see set -e effect:
#blubb

if blubb; then
  echo "Command blubb was succesful."
else 
  echo "Command blubb failed. Exit code: $?"
fi
echo "Script exited normally."

Dimungkinkan untuk menghilangkan pernyataan "lalu" dan menggunakan lebih sedikit baris:

if blubb; then :;
else echo "Command blubb failed. Exit code: $?"; fi
Gustave
sumber
2

Pendekatan lain, yang menurut saya cukup mudah (dan berlaku untuk setopsi lain selain -e):

Manfaatkan $-untuk mengembalikan pengaturan.

Sebagai contoh:

oldopt=$-
set +e
# now '-e' is definitely disabled.
# do some stuff...

# Restore things back to how they were
set -$oldopt

Meskipun untuk -esecara khusus, opsi yang disebutkan orang lain ( || trueatau "dimasukkan ke dalam if") mungkin lebih idiomatis.

jwd
sumber
0

Saya sebenarnya memiliki pertanyaan yang sama baru-baru ini (meskipun saya tidak memposting, saya sempat melakukannya), dan, dari apa yang saya lihat, sepertinya hanya menggunakan set + e sebelum perintah dan set -e sesudahnya bekerja paling elegan. Ini sebuah contoh, mengambil respon dari perintah dan tidak membiarkan kesalahan membuangnya.

#!/bin/sh

args=""
for argcol in $*
do
    args="${args} ${argcol}"
done
fortunevar=""
fortfail=""
{
    set +e
    fortunevar=`fortune $args`
    fortfail=$?
    set -e
} &> /dev/null
if [ $fortfail == 0 ]
then
    echo ${fortunevar}
    say ${fortunevar}
else
    echo misfortune: an illegal option was detected!
    echo misfortune: usage: misfortune [-afilosw] [-m pattern][ [#%] file/directory/all]
fi

Ini mengambil output 'keberuntungan', memeriksa status keluarnya, dan menggemakan dan mengatakannya. Saya pikir ini yang Anda minta, atau setidaknya sesuatu yang serupa? Bagaimanapun, semoga ini membantu.

Addison Crump
sumber
Untuk memperjelas, sedikit dalam tanda kurung keriting diarahkan ke / dev / null adalah apa yang Anda cari, saya percaya. Itu membuat perintah tidak memiliki ouput dan memeriksa status kesalahannya tanpa keluar dari program.
Addison Crump
0

Saya suka memulai subshell jika ingin mengubah sesuatu sementara. Perintah di bawah ini menunjukkan bahwa bad_command pertama diabaikan dan kedua membatalkan eksekusi.

bash -c 'set -e ;\
( set +e; bad_command ; echo still here ) ;\
echo even here ; \
bad_command ; \
echo but not here;'
noonex
sumber