My Ubuntu/Debian-based Linux update POSIX shell script seems to require me not to double quote the string variable with the stored command, which is being executed. As I don't understand this issue, I'd like to ask why that is? And if the code is correct as it is?

Warning: SC2086, wiki, "Double quote to prevent globbing and word splitting."

The script follows, the problematic part is highlighted:


# exit script when it tries to use undeclared variables
set -u

# color definitions
readonly red=$(tput bold)$(tput setaf 1)
readonly green=$(tput bold)$(tput setaf 2)
readonly yellow=$(tput bold)$(tput setaf 3)
readonly white=$(tput bold)$(tput setaf 7)
readonly color_reset=$(tput sgr0)
# to create blocks of texts, I separate them with this line
readonly block_separator='----------------------------------------'

execute_jobs ()
    while [ ${#} -gt 1 ]

        step_number=$(( step_number + 1 ))

        printf '%s\n' "Step #${step_number}: ${green}${job_description}${color_reset}"

        printf '%s\n' "Command: ${yellow}${job_command}${color_reset}"

        printf '%s\n' "${white}${block_separator}${color_reset}"

        # ShellCheck warns me I should double quote the parameter
        # If I did, it would become a string (I think) and I'd get 'command not found' (proven)
        # As I don't understand the issue, I left it as I wrote it, without quotes
        ### shellcheck disable=SC2086

        if sudo ${job_command} # <-- HERE

            printf '\n'
            printf '%s\n\n' "${red}An error occurred.${color_reset}"
            exit 1

        shift 2

execute_jobs \
    'configure packages'                         'dpkg --configure --pending' \
    'fix broken dependencies'                    'apt-get --assume-yes --fix-broken install' \
    'update cache'                               'apt-get update' \
    'upgrade packages'                           'apt-get --assume-yes upgrade' \
    'upgrade packages with possible removals'    'apt-get --assume-yes dist-upgrade' \
    'remove unused packages'                     'apt-get --assume-yes --purge autoremove' \
    'clean up old packages'                      'apt-get autoclean'

You can’t quote the variable here:

if sudo ${job_command}

because you do want word splitting. If you quote, the command becomes (for your first step)

if sudo "dpkg --configure --pending"

and sudo looks for the command dpkg --configure --pending, rather than the command dpkg with the arguments --configure and --pending, as indicated by its error message:

sudo: dpkg --configure --pending: command not found

(try it with extra spaces to make it more explicit).

With the quotes omitted, the shell splits the arguments, and everything works as expected.

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.