Gibt es in bash ein Äquivalent zu "error msg"?

70

In Perl können Sie mit einer Fehlermeldung mit beenden die "some msg". Gibt es einen äquivalenten Einzelbefehl in bash? Im Moment erreiche ich dies mit Befehlen:echo "some msg" && exit 1

PJx
quelle

Antworten:

76

Sie können Ihre eigenen leicht genug rollen:

die() { echo "$*" 1>&2 ; exit 1; }
...
die "Kaboom"
Keith Thompson
quelle
1
+1; Beachten Sie jedoch, dass die ohne Argumente einen unerwünschten Zeilenumbruch ausgibt. Ich mag '{test -n "$ @" && echo "$ @"; Ausfahrt 1; }> & 2 '
William Pursell
4
@WilliamPursell: Sie könnten verwenden printf %s "${@+$@$'\n'}"- Mit anderen Worten, drucken Sie die Argumente gefolgt von einer neuen Zeile, falls vorhanden.
10b0
Wenn ich 6 Jahre später auf diese Antwort zurückblicke, stelle ich fest, dass dies "$*"wahrscheinlich sinnvoller ist als "$@". Das Verhalten ist in den meisten Fällen identisch, unterscheidet sich jedoch für die -n Oops(nicht, dass Sie dies tun möchten).
Keith Thompson
31

Hier ist was ich benutze. Es ist zu klein, um es in eine Bibliothek zu stellen, also muss ich es hunderte Male getippt haben ...

warn () {
    echo "$0:" "$@" >&2
}
die () {
    rc=$1
    shift
    warn "$@"
    exit $rc
}

Verwendung: die 127 "Syntax error"

Tripleee
quelle
15

Dies ist eine sehr nahe an Perls "Würfel" liegende Funktion (jedoch mit Funktionsname):

function die
{
    local message=$1
    [ -z "$message" ] && message="Died"
    echo "$message at ${BASH_SOURCE[1]}:${FUNCNAME[1]} line ${BASH_LINENO[0]}." >&2
    exit 1
}

Und Bash Art zu sterben, wenn die eingebaute Funktion fehlgeschlagen ist (mit Funktionsname)

function die
{
    local message=$1
    [ -z "$message" ] && message="Died"
    echo "${BASH_SOURCE[1]}: line ${BASH_LINENO[0]}: ${FUNCNAME[1]}: $message." >&2
    exit 1
}

Daher speichert Bash alle erforderlichen Informationen in mehreren Umgebungsvariablen:

  • LINENO - aktuell ausgeführte Zeilennummer
  • FUNCNAME - Funktionsstapel aufrufen, erstes Element (Index 0) ist aktuelle Funktion, zweites (Index 1) ist Funktion, die aktuelle Funktion genannt wird
  • BASH_LINENO - Stapel von Zeilennummern aufrufen, wobei der entsprechende FUNCNAME aufgerufen wurde
  • BASH_SOURCE - Array der Quelldatei, in der der entsprechende FUNCNAME gespeichert ist
Sergey Irisov
quelle
5
Sie können die lokale Variable ganz vermeiden mit ${1-Died}- damit können Sie sogar eine leere Zeichenfolge übergeben, und es funktioniert wie erwartet.
Tripleee
4

Ja, so machst du das ziemlich genau.

Sie können anstelle von && ein Semikolon oder eine neue Zeile verwenden, da Sie beenden möchten, ob das Echo erfolgreich ist oder nicht (obwohl ich nicht sicher bin, was dazu führen würde, dass es fehlschlägt).

Das Programmieren in einer Shell bedeutet, viele kleine Befehle (einige eingebaute Befehle, einige winzige Programme) zu verwenden, die eine Sache gut machen, und sie mit Dateiumleitung, Exit-Code-Logik und anderem Kleber zu verbinden.

Es mag seltsam erscheinen, wenn Sie an Sprachen gewöhnt sind, in denen alles mit Funktionen oder Methoden erledigt wird, aber Sie gewöhnen sich daran.

Bonkydog
quelle
Jetzt finde ich einen weiteren unangenehmen Effekt heraus. Während der Echo-Befehl ausgeführt wird, wartet der Interpreter nicht auf den Abschluss, sondern führt gleichzeitig den darunter liegenden Code aus! Folgendes habe ich : CMD1 || (echo 'ERROR MSG'; exit 1); CMD2; CMD3. Wenn CMD1 fehlschlägt, erwarte ich, dass das Echo und das Beenden stattfinden und das Skript beendet wird. Wenn CMD1 jetzt ausfällt, werden CMD2 und CMD3 tatsächlich vor dem Echo ausgeführt. Dies entspricht dem Fehlerprotokoll. Bizarr oder nicht?
PJx
Eigentlich denke ich, dass die Klammern () der Schuldige sein können. Lesen Sie einfach irgendwo, dass sie den Code in einer Subshell ausführen können, was natürlich nicht den gewünschten Effekt hätte. Ich habe gerade meinen Code in einen If-Fi-Block geändert und es hat wie erwartet funktioniert. Kann ich diesen Code aus Neugier zu einem Einzeiler kombinieren?
PJx
2
Verwenden Sie {}statt (), um das Problem mit der Unterschale zu vermeiden. Es ist auch eine gute Idee, Fehler an stderr anstatt an stdout zu senden:CMD1 || { echo 'ERROR MSG' >&2; exit 1; }; CMD2; CMD3
Gordon Davisson
0
# echo pass params and print them to a log file
wlog(){
    # check terminal if exists echo 
    test -t 1 && echo "`date +%Y.%m.%d-%H:%M:%S` [$$] $*"
    # check LogFile and 
    test -z $LogFile || {
      echo "`date +%Y.%m.%d-%H:%M:%S` [$$] $*" >> $LogFile
    } #eof test
 } 
# eof function wlog 


# exit with passed status and message
Exit(){
    ExitStatus=0
    case $1 in
      [0-9]) ExitStatus="$1"; shift 1;;
  esac
    Msg="$*"
    test "$ExitStatus" = "0" || Msg=" ERROR: $Msg : $@"
    wlog " $Msg"
    exit $ExitStatus
}
#eof function Exit
Yordan Georgiev
quelle