3
\$\begingroup\$

I'm new to writing bash scripts and was wondering if I could get someone's advice on a part of the script I'm working on.

Intended purpose of code

Check if a package exists using dpkg, and if it doesn't, offer to install it for the user. This snippet is part of a larger script that installs a particular Conky configuration along with all of its dependencies with minimal effort from the user.

Concerns

  • I feel as though there is a more elegant way to check if a package is installed using dpkg (code was found on Stack Overflow).
  • Is there a better way of handling the (y/n) response?

Here is the code that I am using:

declare -a packages=("conky-all" "lm-sensors");

for i in "${packages[@]}"; do
    if [ $(dpkg-query -W -f='${Status}' $i 2>/dev/null | grep -c "ok installed") -eq 0 ]; then
        echo "$i is not installed, would you like to install it now? (Y/N)";
        read response
        if [ "$response" == "y" ] || [ "$response" == "Y" ]; then
            sudo apt-get install "$i";
        else
            echo "Skipping the installation of $i...";
            echo "Please note that this Conky configuration will not work without the $i package.";
        fi
    else
        echo "The $i package has already been installed.";
    fi
done
\$\endgroup\$
3
\$\begingroup\$

Instead of this:

    if [ $(dpkg-query -W -f='${Status}' $i 2>/dev/null | grep -c "ok installed") -eq 0 ]; then

A better way to write the same thing:

    if ! dpkg-query -W -f='${Status}' $i 2>/dev/null | grep -q "ok installed"; then

Instead of this:

        if [ "$response" == "y" ] || [ "$response" == "Y" ]; then

A simpler way to write is:

        if [[ $response == [yY]* ]]; then

This is not example the same. It will match anything that starts with "y" or "Y". If you want to match strictly only those letters, just drop the * from the pattern:

        if [[ $response == [yY] ]]; then

Finally, all the ; at line endings are unnecessary. The purpose of ; is to separate multiple statements on the same line. Line breaks naturally serve as statement separators.

| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ Thank you very much. Just for the sake of clarity, why are the double brackets necessary for the "if [[ $response == [yY] ]]" statement? \$\endgroup\$ – John P. Apr 29 '15 at 20:05
  • 1
    \$\begingroup\$ [ ... ] cannot match patterns like that. [[ ... ]] is more modern and sophisticated, it can do this. \$\endgroup\$ – janos Apr 29 '15 at 20:07
  • 1
    \$\begingroup\$ Just make it a habit to quote all variable expansions. It's not worth it to save a few quote characters. \$\endgroup\$ – 200_success Apr 30 '15 at 0:55
  • \$\begingroup\$ @200_success I guess you're right. I dropped that point about quoting \$\endgroup\$ – janos Apr 30 '15 at 4:48

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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