Как проанализировать $ QUERY_STRING из CGI-скрипта bash - PullRequest
20 голосов
/ 13 октября 2010

У меня есть скрипт bash, который используется в CGI. CGI устанавливает переменную среды $ QUERY_STRING, читая все, что находится после ? в URL. Например, http://example.com? A = 123 & b = 456 & c = ok устанавливает QUERY_STRING=a=123&b=456&c=ok.

Где-то я обнаружил следующее безобразие:

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

, который установит $ b к тому, что было найдено в $ QUERY_STRING для b. Однако мой сценарий вырос до десяти входных параметров. Есть ли более простой способ автоматического преобразования параметров в $ QUERY_STRING в переменные среды, используемые bash?

Возможно, я просто использую цикл for некоторого вида, но было бы еще лучше, если бы скрипт был достаточно умен, чтобы автоматически определять каждый параметр и, возможно, построить массив, который выглядит примерно так:

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

Как я мог написать код для этого?

Ответы [ 13 ]

0 голосов
/ 31 июля 2015

почему не это

    $ echo "${QUERY_STRING}"
    name=carlo&last=lanza&city=pfungen-CH
    $ saveIFS=$IFS
    $ IFS='&'
    $ eval $QUERY_STRING
    $ IFS=$saveIFS

теперь у вас есть это

    name = carlo
    last = lanza
    city = pfungen-CH

    $ echo "name is ${name}"
    name is carlo
    $ echo "last is ${last}"
    last is lanza
    $ echo "city is ${city}"
    city is pfungen-CH
0 голосов
/ 13 октября 2014

Чтобы обновить это, если у вас последняя версия Bash, вы можете добиться этого с помощью регулярных выражений:

q="$QUERY_STRING"
re1='^(\w+=\w+)&?'
re2='^(\w+)=(\w+)$'
declare -A params
while [[ $q =~ $re1 ]]; do
  q=${q##*${BASH_REMATCH[0]}}       
  [[ ${BASH_REMATCH[1]} =~ $re2 ]] && params+=([${BASH_REMATCH[1]}]=${BASH_REMATCH[2]})
done

Если вы не хотите использовать ассоциативные массивы, просто измените предпоследнюю строку, чтобы сделать то, что вы хотите. Для каждой итерации цикла параметр находится в ${BASH_REMATCH[1]}, а его значение в ${BASH_REMATCH[2]}.

Здесь то же самое, что и функция в коротком тестовом скрипте, который перебирает массив и выводит параметры строки запроса и их значения

#!/bin/bash
QUERY_STRING='foo=hello&bar=there&baz=freddy'

get_query_string() {
  local q="$QUERY_STRING"
  local re1='^(\w+=\w+)&?'
  local re2='^(\w+)=(\w+)$'
  while [[ $q =~ $re1 ]]; do
    q=${q##*${BASH_REMATCH[0]}}
    [[ ${BASH_REMATCH[1]} =~ $re2 ]] && eval "$1+=([${BASH_REMATCH[1]}]=${BASH_REMATCH[2]})"
  done
}

declare -A params
get_query_string params

for k in "${!params[@]}"
do
  v="${params[$k]}"
  echo "$k : $v"
done          

Обратите внимание, что параметры оказываются в массиве в обратном порядке (это ассоциативно, так что это не должно иметь значения).

0 голосов
/ 25 сентября 2014

После правильного ответа я сделал некоторые изменения для поддержки переменных массива, как в этот другой вопрос . Я добавил также функцию декодирования, из-за которой я не могу найти автора, чтобы отдать ему должное.

Код выглядит несколько грязно, но работает. Изменения и другие рекомендации будут с благодарностью.

function cgi_decodevar() {
    [ $# -ne 1 ] && return
    local v t h
    # replace all + with whitespace and append %%
    t="${1//+/ }%%"
    while [ ${#t} -gt 0 -a "${t}" != "%" ]; do
        v="${v}${t%%\%*}" # digest up to the first %
        t="${t#*%}"       # remove digested part
        # decode if there is anything to decode and if not at end of string
        if [ ${#t} -gt 0 -a "${t}" != "%" ]; then
            h=${t:0:2} # save first two chars
            t="${t:2}" # remove these
            v="${v}"`echo -e \\\\x${h}` # convert hex to special char
        fi
    done
    # return decoded string
    echo "${v}"
    return
}

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

for ((i=0; i<${#VARS[@]}; i+=2))
do
  curr="$(cgi_decodevar ${VARS[i]})"
  next="$(cgi_decodevar ${VARS[i+2]})"
  prev="$(cgi_decodevar ${VARS[i-2]})"
  value="$(cgi_decodevar ${VARS[i+1]})"

  array=${curr%"[]"}

  if  [ "$curr" == "$next" ] && [ "$curr" != "$prev" ] ;then
      j=0
      declare var_${array}[$j]="$value"
  elif [ $i -gt 1 ] && [ "$curr" == "$prev" ]; then
    j=$((j + 1))
    declare var_${array}[$j]="$value"
  else
    declare var_$curr="$value"
  fi
done
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...