Search code examples
bashcgi

How to parse $QUERY_STRING from a bash CGI script?


I have a bash script that is being used in a CGI. The CGI sets the $QUERY_STRING environment variable by reading everything after the ? in the URL. For example, http://example.com?a=123&b=456&c=ok sets QUERY_STRING=a=123&b=456&c=ok.

Somewhere I found the following ugliness:

b=$(echo "$QUERY_STRING" | sed -n 's/^.*b=\([^&]*\).*$/\1/p' | sed "s/%20/ /g")

which will set $b to whatever was found in $QUERY_STRING for b. However, my script has grown to have over ten input parameters. Is there an easier way to automatically convert the parameters in $QUERY_STRING into environment variables usable by bash?

Maybe I'll just use a for loop of some sort, but it'd be even better if the script was smart enough to automatically detect each parameter and maybe build an array that looks something like this:

${parm[a]}=123
${parm[b]}=456
${parm[c]}=ok

How could I write code to do that?


Solution

  • Try this:

    saveIFS=$IFS
    IFS='=&'
    parm=($QUERY_STRING)
    IFS=$saveIFS
    

    Now you have this:

    parm[0]=a
    parm[1]=123
    parm[2]=b
    parm[3]=456
    parm[4]=c
    parm[5]=ok
    

    In Bash 4, which has associative arrays, you can do this (using the array created above):

    declare -A array
    for ((i=0; i<${#parm[@]}; i+=2))
    do
        array[${parm[i]}]=${parm[i+1]}
    done
    

    which will give you this:

    array[a]=123
    array[b]=456
    array[c]=ok
    

    Edit:

    To use indirection in Bash 2 and later (using the parm array created above):

    for ((i=0; i<${#parm[@]}; i+=2))
    do
        declare var_${parm[i]}=${parm[i+1]}
    done
    

    Then you will have:

    var_a=123
    var_b=456
    var_c=ok
    

    You can access these directly:

    echo $var_a
    

    or indirectly:

    for p in a b c
    do
        name="var$p"
        echo ${!name}
    done
    

    If possible, it's better to avoid indirection since it can make code messy and be a source of bugs.