8

Here's a simplified version of my script. My question is, How do I return the exit code from apt-get in this case?

#!/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

The output is:

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

Update: I came up with something that works:

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

Is that a good approach?

2 Answers 2

9

Bash's return() can only return numerical arguments. In any case, by default, it will return the exit status of the last command run. So, all you really need is:

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

You don't need to explicitly set a value to be returned since by default a function will return $?. However, that will not work if the first apt command failed and you did not go into the if loop. To make it more robust, use this:

#!/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
}

The general rule is that in order to have a function return the exit status of a particular job and not necessarily the last one it ran, you will need to save the exit status to a variable and return the variable:

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: Actually, as @gniourf_gniourf pointed out in the comments, you could greatly simplify the whole thing using &&:

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

The return value of this function will be one of:

  1. If apt-get -h failed, it will return its exit code
  2. If apt-get -h succeeded, it will return the exit code of sudo apt-get install.
7
  • Sorry, my example was not clear enough. I need a return statement (or some equivalent logic) in my actual script so stuff following this statement is not executed if apt-get was present on this system. If apt-get is not present, it looks for zypper, etc. I guess adding return $? on the next line of your example after sudo apt-get ... might be sufficient. Is that right? Thanks
    – MountainX
    Jul 7, 2013 at 19:12
  • @MountainX see updated answer. The way you have written it (and the way I have written my example) if the apt fails, then its exit status is returned and the function exits, returning the exit value of the at-get. Isn't that what you need?
    – terdon
    Jul 7, 2013 at 19:15
  • 2
    the ret variable is useless. apt-get -h > /dev/null 2>&1 && sudo apt-get install --assume-yes "$@" would do the same. Oh, and use more quotes, especially for $@ Jul 7, 2013 at 19:17
  • @gniourf_gniourf yes indeed, answer updated.
    – terdon
    Jul 7, 2013 at 19:22
  • Thanks for the feedback. I pasted my complete function as I realized that my simplified example wasn't enough. I appreciate any further comments.
    – MountainX
    Jul 7, 2013 at 19:34
1

For completeness, here is my actual function with some modifications as suggested by @terdon and @gniourf_gniourf :

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
}

I appreciate any further suggestions.

1
  • The cmd; if [ $? -eq 0 ]; then ... construct is generally better expressed as if cmd; then ... or even just cmd && ... if the "then" part is just a simple command.
    – tripleee
    Jul 8, 2013 at 6:00

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .