1
\$\begingroup\$

This script simply installs the chosen packages if they're not present on a Linux system using the apt package manager. Notes on improvements of any aspect are welcome!

setup_env.sh

#!/usr/bin/env bash
set -euo pipefail

install_if_not_exist() {
  if dpkg -s "$1" &>/dev/null; then
    PKG_EXIST=$(dpkg -s "$1" | grep "install ok installed")
    if [ -z "$PKG_EXIST" ]; then
      sudo apt install "$1" -y
    fi
  else
    sudo apt install "$1" -y
  fi
}

sudo apt update -y

install_if_not_exist aria2
install_if_not_exist coreutils
install_if_not_exist gawk
install_if_not_exist jq
install_if_not_exist moreutils
install_if_not_exist sed
\$\endgroup\$
5
  • \$\begingroup\$ I don't know bash, and this doesn't merit an answer, but would it be easier to make the list of packages to install an array that you can iterate over? You could then avoid typing install_if_notexist foo every time you want to install a new package. \$\endgroup\$
    – user
    Jun 11, 2021 at 16:07
  • \$\begingroup\$ @user Well I avoid typing by just copy-pasting ;) But yes a loop would help. \$\endgroup\$
    – T145
    Jun 11, 2021 at 16:27
  • \$\begingroup\$ Is there some context behind why you would want to do this? Otherwise, why wouldn't you just invoke apt install, and it would tell you which of the requested packages are already installed (and therefore it won't install them again)? \$\endgroup\$ Jun 11, 2021 at 20:38
  • \$\begingroup\$ Also, why work with one package at a time? apt is more efficient when you install all the packages you want in one transaction. \$\endgroup\$ Jun 11, 2021 at 20:41
  • \$\begingroup\$ @200_success To your last question; true, this was just something I whipped up quickly so I thought it would be a prime review candidate. To the first, yes; I'm automatically installing dependencies across various virtual environments, so I tried to keep it simple. \$\endgroup\$
    – T145
    Jun 11, 2021 at 20:46

2 Answers 2

2
\$\begingroup\$

Good

  • Yay for using a function to contain most of the functionality
  • Good indentation
  • It looks like you're following shellcheck
  • Good names for the variable and function

Suggestions

  • Use double square brackets for conditionals. They will lead to fewer surprises.
  • Instead of repeating the sudo apt install "$1" -y I'd change the if [ -z "$PKG_EXIST" ]... to if [[ -n "$PKG_EXIST" ]]; then; return; fi and move the sudo apt install "$1" -y line to the bottom of the function definition. Coded more fully below.
  • I like to comment the strict mode line(s) since many folks don't realize what this is doing.
  • Check to make sure the function only gets one argument. You might later accidentally put a space into a package name and this would catch that.

rewrite of central function

install_if_not_exist() {
  if dpkg -s "$1" &>/dev/null; then
    PKG_EXIST=$(dpkg -s "$1" | grep "install ok installed")
    if [[ -n "$PKG_EXIST" ]]; then
      return
    fi
  fi
  sudo apt install "$1" -y
}
\$\endgroup\$
3
  • \$\begingroup\$ How would your second suggestion look in code? There are a couple ways I'm interpreting it. \$\endgroup\$
    – T145
    Jun 11, 2021 at 18:25
  • \$\begingroup\$ I added the code I'm suggesting to the answer. \$\endgroup\$
    – chicks
    Jun 11, 2021 at 18:55
  • \$\begingroup\$ Thanks! I figured it was something like this, but got stressed out not seeing the first condition there. \$\endgroup\$
    – T145
    Jun 11, 2021 at 20:40
1
\$\begingroup\$

Using sudo in scripts is an anti-pattern. It can irritate the user with repeated password requests (depending on how sudo is configured).

For this script, it's better to assume (or test) that the user is already sufficiently privileged. And explicitly set PATH at the beginning to avoid trojan horses taking advantage of the escalated privilege:

PATH=/usr/sbin:/usr/bin

The only thing in this script that's not standard POSIX shell is set -o pipefail, so it could easily be made portable and more efficient.

\$\endgroup\$
2
  • 1
    \$\begingroup\$ What happens if the script already has privileges set? Wouldn't that naturally restrict access? If I apply that PATH statement at the head of my script, does that mean sudo can be removed? What could make it more portable and efficient? \$\endgroup\$
    – T145
    Jun 11, 2021 at 20:38
  • \$\begingroup\$ Not sure what you mean when you ask "Wouldn't that naturally restrict access?" I'm suggesting that instead of sudo within the script, then it's better for users to run the script itself using sudo (or other means). In which case sudo in the script isn't necessary. And for scripts run as a superuser, it's wise to set PATH to a known value. \$\endgroup\$ Jun 12, 2021 at 9:55

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.