Wie kann ich den Exit-Code zurückgeben? Fehler: Rückgabe: Lesen: Numerisches Argument erforderlich

7

Hier ist eine vereinfachte Version meines Skripts. Meine Frage ist: Wie kann ich apt-getin diesem Fall den Exit-Code zurückgeben ?

#!/bin/bash
install_auto() {
apt-get -h > /dev/null 2>&1
if [ $? -eq 0 ] ; then
    return $(sudo apt-get install --assume-yes $@)
fi
return 1
}
echo "installing $@"
install_auto "$@"
echo $?
echo "finished"
exit 0

Die Ausgabe ist:

./install_test.sh: line 5: return: Reading: numeric argument required

Update: Ich habe mir etwas ausgedacht, das funktioniert:

return $(sudo apt-get install --assume-yes "$@" >/dev/null 2>&1; echo $?)

Ist das ein guter Ansatz?

MountainX
quelle

Antworten:

7

Bash's return()können nur numerische Argumente zurückgeben. In jedem Fall wird standardmäßig der Exit-Status des letzten Befehlslaufs zurückgegeben. Alles was Sie wirklich brauchen ist:

#!/usr/bin/env bash
install_auto() {
apt-get -h > /dev/null 2>&1
if [ $? -eq 0 ] ; then
    sudo apt-get install --assume-yes $@
fi
}

Sie müssen keinen explizit zurückzugebenden Wert festlegen, da standardmäßig eine Funktion zurückgegeben wird $?. Dies funktioniert jedoch nicht, wenn der erste aptBefehl fehlgeschlagen ist und Sie nicht in die ifSchleife gegangen sind . Verwenden Sie Folgendes, um es robuster zu machen:

#!/usr/bin/env bash
install_auto() {
apt-get -h > /dev/null 2>&1
ret=$?
if [ $ret -eq 0 ] ; then
    ## If this is executed, the else is ignored and $? will be
    ## returned. Here, $?will be the exit status of this command
    sudo apt-get install --assume-yes $@
else
    ## Else, return the exit value of the first apt-get
    return $ret
fi
}

Die allgemeine Regel lautet, dass Sie den Exit-Status in einer Variablen speichern und die Variable zurückgeben müssen, damit eine Funktion den Beendigungsstatus eines bestimmten Jobs und nicht unbedingt den zuletzt ausgeführten zurückgibt:

function foo() {
    run_a_command arg1 arg2 argN
    ## Save the command's exit status into a variable
    return_value= $?

    [the rest of the function  goes here]
    ## return the variable
    return $return_value
}

EDIT: Wie @gniourf_gniourf in den Kommentaren betonte, können Sie das Ganze erheblich vereinfachen, indem Sie &&:

install_auto() {
  apt-get -h > /dev/null 2>&1 &&
  sudo apt-get install --assume-yes $@
}

Der Rückgabewert dieser Funktion ist einer von:

  1. Wenn dies apt-get -h fehlschlägt, wird der Exit-Code zurückgegeben
  2. Wenn dies apt-get -herfolgreich ist, wird der Exit-Code von zurückgegeben sudo apt-get install.
terdon
quelle
Entschuldigung, mein Beispiel war nicht klar genug. Ich benötige eine return-Anweisung (oder eine äquivalente Logik) in meinem eigentlichen Skript, damit Dinge, die dieser Anweisung folgen, nicht ausgeführt werden, wenn apt-get auf diesem System vorhanden war. Wenn apt-get nicht vorhanden ist, sucht es nach Zypper usw. Ich denke, das Hinzufügen return $?in der nächsten Zeile Ihres Beispiels nach sudo apt-get ...könnte ausreichen. Ist das richtig? Vielen Dank
MountainX
@MountainX siehe aktualisierte Antwort. Wenn Sie es geschrieben haben (und wie ich mein Beispiel geschrieben habe), wenn das aptfehlschlägt, wird sein Exit-Status zurückgegeben und die Funktion wird beendet, wobei der Exit-Wert von zurückgegeben wird at-get. Ist es nicht das, was du brauchst?
Terdon
2
Die retVariable ist nutzlos. apt-get -h > /dev/null 2>&1 && sudo apt-get install --assume-yes "$@"würde das gleiche tun. Oh, und verwenden Sie mehr Anführungszeichen, besonders für$@
gniourf_gniourf
@gniourf_gniourf ja in der Tat, Antwort aktualisiert.
Terdon
Danke für die Rückmeldung. Ich habe meine gesamte Funktion eingefügt, als mir klar wurde, dass mein vereinfachtes Beispiel nicht ausreicht. Ich freue mich über weitere Kommentare.
MountainX
1

Der Vollständigkeit halber ist hier meine eigentliche Funktion mit einigen Änderungen, wie von @terdon und @gniourf_gniourf vorgeschlagen:

install_auto() {
    if [ ! $# -gt 0 ] ; then
        echo "usage: $0 package_name [package_name ...]"
    fi 

    apt-get -h > /dev/null 2>&1
    if [ $? -eq 0 ] ; then
        if [ -f "$@" ] || [[ "$@" =~ '/' ]] ; then
            sudo gdebi -n "$@"
            return $?
        else    
            sudo apt-get install --assume-yes "$@"
            return $?
        fi
    fi

    zypper help > /dev/null 2>&1
    if [ $? -eq 0 ] ; then
            sudo zypper --non-interactive --no-gpg-checks --quiet install --auto-agree-with-licenses "$@"
            return $?
    fi

    #may check other package managers in the future

    echo "ERROR: package manager not found"
    return 255
}

Ich freue mich über weitere Vorschläge.

MountainX
quelle
Das cmd; if [ $? -eq 0 ]; then ...Konstrukt wird im Allgemeinen besser ausgedrückt als if cmd; then ...oder sogar nur, cmd && ...wenn der "dann" -Teil nur ein einfacher Befehl ist.
Tripleee