简体   繁体   中英

A better way to write an if statement in Bash

Having several scripts which follow the below pattern, and I'm curious if you folks have suggestions on reducing the number of lines or if you're doing this more streamlined?

What I don't like necessarily is that I'm using too many $? checks, and end up with nested if loops - not sure if that is a bad thing though.

Code I'm looking to optimize but still keep the functionality is like this:

wget -V > /dev/null 2>&1
if [ $? -ne 0 ]; then
    apt install wget
    if [ $? -ne 0 ]; then
        "failed to install wget" 
    fi
fi

oneliner using hash :

hash wget 2>/dev/null || echo 'wget is not installed'

If you need to install, you can do

hash wget 2>/dev/null || apt install -y wget || echo 'failed to install wget'

again, oneliner.

More specifically, hash is a reliable way in shell to check if a binary exists in $PATH . you can check info about hash as following:

$ help hash
hash: hash [-lr] [-p pathname] [-dt] [name ...]
    Remember or display program locations.

    Determine and remember the full pathname of each command NAME.  If
    no arguments are given, information about remembered commands is displayed.

    Options: ...

    Exit Status:
    Returns success unless NAME is not found or an invalid option is given.

In general, you don't need to check $? explicitly unless you are looking for a particular non-zero exit code. You can rewrite your code as:

if ! wget -V &> /dev/null; then
  if ! apt install wget; then
     echo "failed to install wget" 
  fi
fi

Or, even more concisely:

wget -V &> /dev/null || apt install wget || echo "failed to install wget"

I try to get the big picture behind, and I think you try to re-invent the wheel.

The said wheel is command-not-found on and derivatives.

It makes proposition when a command failed automatically.

You just have to do :

 apt-get install command-not-found
 update-command-not-found
 wget -V # or any missing command

If this is an installer script, don't check, just install. Any packages that are already installed will be skipped anyways:

apt install wget jq texlive-latex-base || exit 1

If this is a normal script, don't install missing dependencies , especially not without the user's consent. This is not the script's job, and it's much more intrusive than helpful.

If you still want to do it, just put it in a function. Here's an example:

require() {
  # Assume $1 is command and $3 is package (or same as command)
  set -- "$1" from "${3:-$1}"
  if ! { type "$1" > /dev/null 2>&1 || apt install "$3"; }
  then
    echo "$1 was missing, but installation of $3 failed" >&2
    exit 1
  fi
}

require wget
require jq
require latex from texlive-latex-base

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM