Search code examples
arraysbashindexingcasevariable-assignment

bash case stmt - pattern not matching


This conundrum is stumping me. Why can't bash's case stmt match the pattern variable and properly assign the array's index value to the command variable?

Script Code:

#!/usr/bin/env bash

function run() {
    local       command SearchPattern="a2522866d08d848dd99b5997ad08eb936f68ce91"
    local -A    shaCommands=(
                    ['md5sum']=32
                    ['sha1sum']=40
                    ['sha224sum']=56
                    ['sha256sum']=64
                    ['sha384sum']=96
                    ['sha512sum']=128
                )

    printf "\${#SearchPattern}=[%s]\n" "${#SearchPattern}"
    declare -p shaCommands
    case ${#SearchPattern} in
        ${shaCommands['md5sum']} ) command="${!shaCommands['md5sum']}" ;;
        ${shaCommands['sha1sum']} ) command="${!shaCommands['sha1sum']}" ;;
        ${shaCommands['sha224sum']} ) command="${!shaCommands['sha224sum']}" ;;
        ${shaCommands['sha256sum']} ) command="${!shaCommands['sha256sum']}" ;;
        ${shaCommands['sha384sum']} ) command="${!shaCommands['sha384sum']}" ;;
        ${shaCommands['sha512sum']} ) command="${!shaCommands['sha512sum']}" ;;
        * ) printf "unrecognized checksum length=[%d] for [%s]\n" \
                "${#SearchPattern}" "${SearchPattern}"
            return $Fail
        ;;
    esac
    printf "command=[%s]\n" "${command}"
}

run

The output shows the case patterns are never matched - it should match on the ${shaCommands['sha1sum']} ) pattern - so $command is never assigned ...

${#SearchPattern}=[40]
declare -A shaCommands=([sha256sum]="64" [sha512sum]="128" [sha1sum]="40" [sha384sum]="96" [md5sum]="32" [sha224sum]="56" )
command=[]

Solution

  • The case statement matches (you can confirm with set -x), but the assignment to command after the match is empty. "${!shaCommands['sha1sum']}" does not get the index of the array element like you want it to, because that expansion to get the indices of the array only works for ${!name[@]} or ${!name[*]} according to the manual.

    ${!name[@]}
    ${!name[*]}
    If name is an array variable, expands to the list of array indices (keys) assigned in name. 
    If name is not an array, expands to 0 if name is set and null otherwise. 
    When ‘@’ is used and the expansion appears within double quotes, each key 
    expands to a separate word.
    

    In other cases, ${!var} is an indirect reference (see Parameter Expansion) where the value of var is used as the name of a variable to reference. ${shaCommands['sha1sum']} has a value of 40, so ${!shaCommands['sha1sum']} is interpreted as ${40} which is not set in your command, so you get an empty string from the expansion.

    You can simply use command=sha1sum instead. You're already hardcoding the key that you use to access the array, so your attempted solution isn't really any more robust than just hardcoding the command value.