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?

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.

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.


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
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.