2010-10-12 11 views
16

मेरे पास एक सीजीआई में उपयोग की जाने वाली एक बैश स्क्रिप्ट है। सीजीआई यूआरएल में ? के बाद सब कुछ पढ़ कर $ QUERY_STRING पर्यावरण चर सेट करता है। उदाहरण के लिए, http://example.com?a=123&b=456&c=okQUERY_STRING=a=123&b=456&c=ok सेट करता है।

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

जो $ करने के लिए ख जो कुछ b के लिए $ QUERY_STRING में पाया गया था सेट हो जाएगा:

कहीं मैं निम्नलिखित कुरूपता पाया। हालांकि, मेरी लिपि में दस से अधिक इनपुट पैरामीटर हैं। क्या $ QUERY_STRING में मानकों को स्वचालित रूप से बाश द्वारा उपयोग किए जाने वाले पर्यावरण चर में कनवर्ट करने का कोई आसान तरीका है?

हो सकता है कि मैं सिर्फ किसी प्रकार की पाश के लिए एक का उपयोग करेंगे, लेकिन अगर स्क्रिप्ट बहुत चालाक स्वचालित रूप से प्रत्येक पैरामीटर पता लगाने के लिए और शायद एक सरणी है कि कुछ इस तरह दिखता बना था तो यह और भी बेहतर होगा:

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

मैं ऐसा करने के लिए कोड कैसे लिख सकता हूं?

+0

मैं सिर्फ देखा है कि मैं वास्तव में बैश 3. पर अटक कर रहा हूँ किसी को भी करता है एक सरल, सुरक्षित समाधान है कि साहचर्य सरणियों शामिल नहीं होगा है? – User1

+1

सहयोगी सरणी के विकल्प के लिए मेरा संपादित उत्तर देखें (यह भी सुनिश्चित करें कि मैंने जिस पृष्ठ से लिंक किया है ([BashFAQ/006] (http://mywiki.wooledge.org/BashFAQ/006)) –

+0

यह लिंक मदद करेगा आप आसानी से अपनी समस्या को हल करने के लिए http://stackoverflow.com/questions/17021640/how-to-extract-the-data-using-sed-command – amar

उत्तर

30

बैश 4 में एक हैश/शब्दकोश में बचा सकता है इसे आज़माएं:

:

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

अब आप इस राशि

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

बैश 4 में, जो साहचर्य सरणियों है, तो आप ऐसा कर सकते हैं (जैसा कि ऊपर बनाया सरणी का उपयोग करके):

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

जो आप इस दे देंगे:

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

संपादित करें:

बैश में अविवेक का उपयोग करने के 2 और बाद में (ऊपर बनाए गए parm सरणी का उपयोग करके):

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

तो फिर तुम होगा:

var_a=123 
var_b=456 
var_c=ok 

आप इन सीधे पहुंच सकते हैं:

echo $var_a 

या परोक्ष रूप से:

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

संभव हो तो, यह avoid indirection करने के लिए बेहतर है, क्योंकि यह कोड गन्दा बना सकते हैं और बग का स्रोत बनें।

+1

+1। लेकिन लूप को प्रस्तुत सभी विधियां कि सरणी दोबारा कुंजी को व्यवस्थित करने में विफल रहता है। प्रत्येक घटना पिछले को ओवरराइट कर देगी। उदाहरण के लिए, एक = 1 और ए = 2 और ए = एक्स के परिणामस्वरूप पार्म [ए] = एक्स – MestreLion

+0

@ मेस्ट्रेएलियन: आप बार-बार कुंजी की संभावना से निपटने के लिए तर्क जोड़ सकते हैं, लेकिन आपको यह तय करना होगा कि आप उनके साथ कैसे निपटना चाहते हैं। आप पहले उदाहरण या अंतिम उदाहरण या संचय की कुछ विधि कर सकते हैं। –

+1

'parm = ($ QUERY_STRING) 'शब्द' QUERY' के विस्तार से ग्लोबबिंग के परिणामस्वरूप शब्दों को विषय देता है, जो शायद अवांछित है। एक और मजबूत विकल्प जो आपको '$ IFS' को सहेजने और पुनर्स्थापित करने की परेशानी बचाता है:' IFS = '& =' read -ra parm <<< "$ QUERY_STRING" ' सभी-अपरकेस खोल- परिवर्तनीय नामों के लिए [पर्यावरण चर और विशेष खोल चर के साथ संघर्ष से बचें] (http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap08.html#tag_08_01)। – mklement0

14

आप को IFS का उपयोग करके नीचे तोड़ सकते हैं। उदाहरण के लिए, यह &

$ QUERY="a=123&b=456&c=ok" 
$ echo $QUERY 
a=123&b=456&c=ok 
$ IFS="&" 
$ set -- $QUERY 
$ echo $1 
a=123 
$ echo $2 
b=456 
$ echo $3 
c=ok 

$ array=([email protected]) 

$ for i in "${array[@]}"; do IFS="=" ; set -- $i; echo $1 $2; done 
a 123 
b 456 
c ok 

के लिए सेटिंग और तुम

$ declare -A hash 
$ for i in "${array[@]}"; do IFS="=" ; set -- $i; hash[$1]=$2; done 
$ echo ${hash["b"]} 
456 
+1

+1 'सेट - $ var' चाल के लिए +1 .. बहुत साफ;) – MestreLion

+0

सिवाय इसके कि आप शब्द-विभाजन पर भरोसा करते हैं, कृपया अपने परिवर्तनीय संदर्भों को दोबारा उद्धृत करें। ध्यान दें कि 'सेट - $ QUERY' शब्द' $ QUERY' में ग्लोबिंग के अधीन बनाता है, जो शायद अवांछित है। [पर्यावरण चर और विशेष खोल चर के साथ संघर्ष से बचने के लिए] (http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap08.html#tag_08_01) के लिए सभी अपरकेस खोल-चर नामों का उपयोग न करना बेहतर है। – mklement0

+0

@ mklement0: यह शब्द-विभाजन पर निर्भर करता है, विशेष रूप से '& 'पर विभाजित होने पर। Globbing कोई समस्या नहीं है क्योंकि क्वेरी स्ट्रिंग url-encoded है। – MSalters

1

सीजीआई क्वेरी स्ट्रिंग को संभालने का एक अच्छा तरीका Haserl का उपयोग करना है जो आपके बैश सीजीआई स्क्रिप्ट के चारों ओर एक रैपर के रूप में कार्य करता है, और सुविधाजनक और सुरक्षित क्वेरी स्ट्रिंग पार्सिंग प्रदान करता है।

2

मैं एक स्क्रिप्ट में एसईडी आदेश पैक:

$ बिल्ली getvar.sh

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

और मैं के रूप में अपने मुख्य cgi से यह कहते हैं:

id=`./getvar.sh id` 
ds=`./getvar.sh ds` 
dt=`./getvar.sh dt` 

... आदि, आदि - आपको विचार मिलता है।

मेरे लिए एक बहुत ही बुनियादी व्यस्त उपकरण उपकरण (इस मामले में मेरा पीवीआर) के साथ भी काम करता है।

+1

। आप वास्तव में, वास्तव में चर के चारों ओर डबल उद्धरण का उपयोग करना चाहिए। – tripleee

0

सही उत्तर के बाद, मैंने this other question जैसे सरणी चर का समर्थन करने के लिए कुछ बदलाव किए हैं। मैंने एक डिकोड फ़ंक्शन भी जोड़ा जिसमें से मुझे कुछ क्रेडिट देने के लिए लेखक नहीं मिल सका।

कोड कुछ हद तक गन्दा दिखाई देता है, लेकिन यह काम करता है। परिवर्तन और अन्य सिफारिशों की सराहना की जाएगी।

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 
0

तारीख को यह ऊपर लाने के लिए, आप एक हाल ही में बैश संस्करण है तो आप नियमित अभिव्यक्ति के साथ इस लक्ष्य को हासिल कर सकते हैं:

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

@starfy इसके लिए धन्यवाद लेकिन यह कुछ वर्णों के साथ काम नहीं करता है जो पैरामीटर मानों में स्वीकार्य हैं, उदा। सरल हाइफ़न "-"। ऐसे पैरामीटर को पार्स करते समय - उदा। पी = foo-bar - केवल मान का पहला भाग लौटाया जाता है (foo)। – giacecco

0

क्यों नहीं इस

$ 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

यह खतरनाक है - * किसी भी * चर * स्क्रिप्ट से वेरिएबल उन पैराम्स द्वारा फिर से लिखा जा सकता है। –

1

मैं बस & की जगह होता है;।

a=123;b=456;c=ok 

तो अब तुम सिर्फ जरूरत का मूल्यांकन करने और अपने वार्स पढ़ें::

eval `echo "${QUERY_STRING}"|tr '&' ';'` 
echo $a 
echo $b 
echo $c 
+0

यह केवल एक सुरक्षा जोखिम नहीं है, बल्कि नाजुक भी है, यह देखते हुए कि मूल्यों में स्वयं ''' '' '' '' हो सकता है या '~' से शुरू हो सकता है। – mklement0

3

कृपया बुराई eval कबाड़ का उपयोग नहीं करते ऐसा लगता है कि कुछ करने के लिए हो जाएगा।सभी लिस्टिंग

declare -A param 
while IFS='=' read -r -d '&' key value; do 
    param["$key"]=$value 
done <<<"${QUERY_STRING:+"${QUERY_STRING}&"}" 

:

declare -A param 
while IFS='=' read -r -d '&' key value && [[ -n "$key" ]]; do 
    param["$key"]=$value 
done <<<"${QUERY_STRING}&" 

आप कुंजी की जांच पसंद नहीं है, तो आप इस बजाय कर सकता है:

का तरीका यहां बताया मज़बूती से स्ट्रिंग पार्स और एक साहचर्य सरणी प्राप्त कर सकते हैं सरणी से चाबियाँ और मान:

for key in "${!param[@]}"; do 
    echo "$key: ${param[$key]}" 
done 
1

QUERY_STRING की सामग्री को ba में परिवर्तित करने के लिए , बी = 456; ग = ठीक जो eval तो वर्तमान खोल में मूल्यांकन करता

eval $(echo ${QUERY_STRING//&/;}) 

भीतरी कदम है, echo ${QUERY_STRING//&/;}, अर्धविराम एक = 123 के उत्पादन के साथ सभी ऐम्परसेंड विकल्प: श चर निम्न आदेश का उपयोग।

परिणाम तब बैश चर के रूप में उपयोग किया जा सकता है।

echo $a 
echo $b 
echo $c 

मान्यताओं हैं:

  • मूल्यों '&' शामिल नहीं होगा
  • मान होते हैं कभी नहीं होगा ';'
  • QUERY_STRING दुर्भावनापूर्ण कोड कभी नहीं होगा
संबंधित मुद्दे