Bash – Simultaneously check for empty output and successful exit status

bashcommand-substitutionerror handlingexit-statusshell-script

I'd like to write the following test in an installer script1:

if [ -n "`/etc/grub.d/30_os-prober`" ]; then
    install_dual_boot
else
    install_linux_only
fi

However, it's also possible that 30_os-prober produces no output because it somehow failed to complete. If 30_os-prober fails with a non-zero exit status, it would be safer to assume the a dual-boot situation.

How can I check that 30_os-prober produced no output successfully?

Basically, I would like to obtain an effect similar to…

if [ -n "`/etc/grub.d/30_os-prober`" ]; then
    # Do stuff for a dual-boot machine
    install_dual_boot
elif ! /etc/grub.d/30_os-prober >/dev/null; then
    # OS probe failed; assume dual boot out of abundance of caution
    install_dual_boot
else
    install_linux_only
fi

… but without running the same command twice.


1 Background information: 30_os-prober comes with GRUB2, and the script I am writing is part of my custom configuration for FAI.

Best Answer

First of all, while they are functionally equivalent, $(…) is widely considered to be clearer than `…` — see this, this, and this.  Secondly, you don’t need to use $? to check whether a command succeeded or failed.  My attention was recently drawn to Section 2.9.1, Simple Commands of The Open Group Base Specifications for Shell & Utilities (Issue 7):

A "simple command" is a sequence of optional variable assignments and redirections, in any sequence, optionally followed by words and redirections, terminated by a control operator.

When a given simple command is required to be executed …
                          ⋮                                                                                (blah, blah, blah …)

If there is a command name, execution shall continue as described in Command Search and Execution.  If there is no command name, but the command contained a command substitution, the command shall complete with the exit status of the last command substitution performed.  …

For example,

  • the exit status of the command

    ls -ld "module_$(uname).c"
    

    is the exit status from the ls, but

  • the exit status of the command

    myfile="module_$(uname).c"
    

    is the exit status from the uname.

So ferada’s answer can be streamlined a bit:

if output=$(/etc/grub.d/30_os-prober)  &&  [ -z "$output" ]
    # i.e., if 30_os-prober successfully produced no output
then
    install_linux_only
else
    install_dual_boot
fi

Note that it is good practice to use all-upper-case names only for environment variables (or variables to be visible throughout the script).  Variables of limited scope are usually named in lower case (or, if you prefer, camelCase).

Related Question