One year ago I asked for a yearly revision of my Interactive Linux upgrade script.

There is nothing new to the conditions, therefore please read the original question before you decide to comment and / or vote to close as unclear.

Additional notes:

  • The script will always run interactively as I want to have full control.

  • The script will be placed on 3 machines only, so I don't need much of generalization.

  • As my POSIX shell scripting abilities get better, I would very much like to get further incentives.

Edited slightly to avoid echo and to provide some information about the system and hardware. You can answer my original question if you are already in progress of writing it. No problem with that.


set -o nounset

# friendly computer description
readonly computer_description='Vlasta - Laptop - Main'

# color definitions
readonly bold=$(tput bold)
readonly bold_red=${bold}$(tput setaf 1)
readonly bold_green=${bold}$(tput setaf 2)
readonly bold_yellow=${bold}$(tput setaf 3)
readonly bold_blue=${bold}$(tput setaf 4)
readonly bold_magenta=${bold}$(tput setaf 5)
readonly bold_cyan=${bold}$(tput setaf 6)
readonly bold_white=${bold}$(tput setaf 7)
readonly nocolor=$(tput sgr0)

# to create clear blocks of texts, we separate them with this
readonly block_separator='----------------------------------------'

    # process the given arguments as pairs
    while [ "${#}" -gt 1 ]
        # increase and print the step number along with description
        step_number=$((step_number + 1))
        printf '%s\n' "Step #${step_number}: ${bold_green}${1}${nocolor}"

        # print the command to be run
        printf '%s\n' "Command: ${bold_yellow}${2}${nocolor}"

        printf '%s\n' "${bold_white}${block_separator}${nocolor}"

        # run the actual command
        # ShellCheck mistakenly things we should double quote the parameter
        # if we did, it would become a string and we'd get command not found
        # shellcheck disable=SC2086
        if sudo ${2}
            printf '\n'
            printf '%s\n\n' "${bold_red}An error occurred.${nocolor}"
            exit 1

        # move to another pair of arguments
        shift 2

distro_name=$(lsb_release --id | awk '{ print $3 }')
release_version=$(lsb_release --release | awk '{ print $2 }')
hostname=$(cat /etc/hostname)

printf '\n%s\n' "Friendly: ${bold_magenta}${computer_description}${nocolor}"
printf '%s\n' "Distro  : ${bold_magenta}${distro_name} ${release_version}${nocolor}"
printf '%s\n' "Hostname: ${bold_magenta}${hostname}${nocolor}"
printf '%s\n\n' "${bold_white}${block_separator}${nocolor}"

# the sudo password request shall proceed AFTER computer / hostname
# this is because the same script will always run in sequence on 3 computers
if [ "$(id --user)" -ne 0 ]
    sudo sh -c ":" || exit 1

printf '%s' "${bold_cyan}"
sudo dmidecode --type 1 | grep 'System Information' --after 8
printf '%s\n\n' "${bold_white}${block_separator}${nocolor}"

# execute all jobs in one go
execute_jobs \
    'configure packages'                         'dpkg --configure --pending' \
    'fix broken dependencies'                    'apt-get --fix-broken install' \
    'update cache'                               'apt-get update' \
    'upgrade packages'                           'apt-get upgrade' \
    'upgrade packages with possible removals'    'apt-get dist-upgrade' \
    'remove unused packages'                     'apt-get --purge autoremove' \
    'clean up old packages'                      'apt-get autoclean'

1 Answer 1


This looks pretty good already, I don't have anything major to add, only some ideas:

  1. POSIX only supports short options. If a command and its short options are defined in the POSIX specifications, e.g. id -u, always adhere to the short options usage. It's a good idea to use the long options otherwise.
  2. You could test for the existence of all utilities not found in the POSIX specifications and fail early if any were not executable. Maybe wrap this inside a exec_non_posix_command function? The challenge is in checking for the options also.
  3. Your method of getting the distro name and release version is fine. A shorter way is distro_release=$(lsb_release --id --release --short | xargs), but I can't vouch for its robustness, as I don't know if the --short option is supported from the very first version of lsb_release and if the inherent assumption about the distributor ID and release ordering wouldn't be violated.

Your Answer

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

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