Search code examples
bashswitch-statementstring-substitution

Why does my variable work in a test statement, but not in a case statement until I use echo to read it into itself?


I have a line with a comment. I use parameter substitution to condition the line into a variable "source". A test statement shows that the value of source is "Simple:", but the case statement can't match it. If I use command substitution to "source=$(echo $source)", test says it matches, like before, and the case statement works now. Am I missing something fundamental, should I not use parameter substitution to do this, or is this weird? Bash version: GNU bash, version 4.4.20(1)-release (x86_64-pc-linux-gnu). Thanks for taking a look.

Piping the line to sed with echo works as expected. If no parameter substitution is performed on a variable, case works as expected. Example: line="Simple:" and case $line in ... no issues.

#!/bin/bash

line="Simple: #comment and space to be removed"
source=${line//#*}
source=${source//^[[:space:]]*}
source=${source//*[[:space:]]$}

[[ $source =~ 'Simple:' ]] && echo -e "\n1st test match" || echo -e "\nno 1st test match"

case $source in
    'Simple:')  
        ops="Simple"
        echo -e "\n1st try case match.  Ops is $ops"
    ;;
    *)
        echo -e "\nno natch in 1st case"
    ;;
esac

source=$(echo $source)

[[ $source =~ 'Simple:' ]] && echo -e "\n2nd test match" || echo -e "\nno 2nd test match"

case $source in
    'Simple:')  
        ops="Simple"
        echo -e "\n2nd try case match.  Ops is $ops"
    ;;
    *)
        echo -e "\nno match 2nd case"
    ;;
esac

I expect "Simple:" would match in the first case statement, but it doesn't until I run "source=$(echo $source)".


Solution

  • Quoting from man bash:

    ${parameter/pattern/string}

    Pattern substitution. The pattern is expanded to produce a pattern just as in pathname expansion, Parameter is expanded and the longest match of pattern against its value is replaced with string. ...

    That means, these lines:

    source=${source//^[[:space:]]*}
    source=${source//*[[:space:]]$}
    

    do nothing at all, ^ and $ doesn't work in pathname expansion; the pattern is not a regex. source=$(echo $source) makes it work because since $source is not in double-quotes, its value undergoes word splitting and the space at the end gets lost.

    The proper way of doing this using parameter expansions is:

    source=${line%%#*}
    source=${source#${source%%[^[:space:]]*}}
    source=${source%${source##*[^[:space:]]}}