web-dev-qa-db-ja.com

この特定のケースで文字列変数を引用する必要がないのはなぜですか?

私のUbuntu/DebianベースのLinuxアップデートPOSIXシェルスクリプトでは、実行中の保存されたコマンドで文字列変数を二重引用符で囲まない必要があるようです。私はこの問題を理解していないので、それがなぜであるかを尋ねたいと思います。そして、コードがそのまま正しいかどうか?

警告:SC2086、 wiki 、「グロブと単語の分割を防ぐために二重引用符で囲みます。」

スクリプトが続き、問題のある部分が強調表示されます。

#!/bin/sh

# 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='----------------------------------------'

step_number=0
execute_jobs ()
{
    while [ ${#} -gt 1 ]
    do
        job_description=${1}
        job_command=${2}

        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}"

        # RUN THE ACTUAL COMMAND
        # 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
        then
            printf '\n'
        else
            printf '%s\n\n' "${red}An error occurred.${color_reset}"
            exit 1
        fi

        shift 2
    done
}

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'
2

ここで変数を引用することはできません。

if Sudo ${job_command}

do単語分割が必要だからです。引用すると、コマンドは(最初のステップで)になります

if Sudo "dpkg --configure --pending"

Sudoは、エラーメッセージで示されているように、引数dpkg --configure --pendingおよび--configureを持つコマンドdpkgではなく、コマンド--pendingを検索します。

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

(より明確にするために、余分なスペースを入れて試してください)。

引用符を省略すると、シェルは引数を分割し、すべてが期待どおりに機能します。

3
Stephen Kitt