कैसे कर्ल कमांड के लिए डेटा urlencode करने के लिए?


319

मैं परीक्षण के लिए एक बैश स्क्रिप्ट लिखने की कोशिश कर रहा हूं जो एक पैरामीटर लेता है और इसे कर्ल के माध्यम से वेब साइट पर भेजता है। मुझे यह सुनिश्चित करने के लिए कि विशेष वर्ण ठीक से संसाधित किए गए हैं, मान को आग्रह करने की आवश्यकता है। इसे करने का बेहतरीन तरीका क्या है?

यहाँ मेरी मूल स्क्रिप्ट अब तक है:

#!/bin/bash
host=${1:?'bad host'}
value=$2
shift
shift
curl -v -d "param=${value}" http://${host}/somepath $@


जवाबों:


394

का उपयोग करें curl --data-urlencode; से man curl:

यह डेटा पोस्ट करता है, --dataअपवाद के साथ अन्य विकल्पों के समान है जो URL-एन्कोडिंग करता है। CGI- आज्ञाकारी होने के लिए, <data>भाग को एक विभाजक और सामग्री विनिर्देश के नाम के साथ शुरू करना चाहिए।

उदाहरण का उपयोग:

curl \
    --data-urlencode "paramName=value" \
    --data-urlencode "secondParam=value" \
    http://example.com

अधिक जानकारी के लिए मैन पेज देखें ।

इसके लिए कर्ल 7.18.0 या नए (जनवरी 2008 को रिलीज़) की आवश्यकता होती है । उपयोग curl -Vआपके पास कौन सा संस्करण है यह जांचने के लिए ।

आप क्वेरी स्ट्रिंग को अच्छी तरह से एन्कोड कर सकते हैं :

curl -G \
    --data-urlencode "p1=value 1" \
    --data-urlencode "p2=value 2" \
    http://example.com
    # http://example.com?p1=value%201&p2=value%202

5
केवल HTTP POST के लिए काम करता है। यहाँ दस्तावेज़ीकरण: curl.haxx.se/docs/manpage.html#--data-urlencode
स्टेन जेम्स

82
@StanJames यदि आप इसका उपयोग करते हैं तो कर्ल भी GET अनुरोध के लिए एन्कोडिंग कर सकते हैं। curl -G --data-urlencode "blah=df ssdf sdf" --data-urlencode "blah2=dfsdf sdfsd " http://whatever.com/whatever
केबर्ग

13
@kberg वास्तव में, यह केवल क्वेरी डेटा के लिए काम करेगा। कर्ल एक 'जोड़ देंगे?' इसके बाद urlencoded Params। यदि आप कुछ url पोस्टफ़िक्स (जैसे CouchDB GET कुछ दस्तावेज़ आईडी के लिए) urlencode करना चाहते हैं, तो '--data-urlencode' काम नहीं करेगा।
बोकेह

1
के लिए काम नहीं करता है curl --data-urlencode "description=![image]($url)" www.example.com। कोई विचार क्यों? `
खुर्शीद आलम


179

यहाँ शुद्ध बीएएस उत्तर है।

rawurlencode() {
  local string="${1}"
  local strlen=${#string}
  local encoded=""
  local pos c o

  for (( pos=0 ; pos<strlen ; pos++ )); do
     c=${string:$pos:1}
     case "$c" in
        [-_.~a-zA-Z0-9] ) o="${c}" ;;
        * )               printf -v o '%%%02x' "'$c"
     esac
     encoded+="${o}"
  done
  echo "${encoded}"    # You can either set a return variable (FASTER) 
  REPLY="${encoded}"   #+or echo the result (EASIER)... or both... :p
}

आप इसे दो तरीकों से उपयोग कर सकते हैं:

easier:  echo http://url/q?=$( rawurlencode "$args" )
faster:  rawurlencode "$args"; echo http://url/q?${REPLY}

[संपादित]

यहाँ मैचिंग रॉर्लडब्लास्क () फ़ंक्शन है, जो - सभी विनय के साथ - कमाल है।

# Returns a string in which the sequences with percent (%) signs followed by
# two hex digits have been replaced with literal characters.
rawurldecode() {

  # This is perhaps a risky gambit, but since all escape characters must be
  # encoded, we can replace %NN with \xNN and pass the lot to printf -b, which
  # will decode hex for us

  printf -v REPLY '%b' "${1//%/\\x}" # You can either set a return variable (FASTER)

  echo "${REPLY}"  #+or echo the result (EASIER)... or both... :p
}

मिलान सेट के साथ, अब हम कुछ सरल परीक्षण कर सकते हैं:

$ diff rawurlencode.inc.sh \
        <( rawurldecode "$( rawurlencode "$( cat rawurlencode.inc.sh )" )" ) \
        && echo Matched

Output: Matched

और अगर आप वास्तव में महसूस करते हैं कि आपको एक बाहरी उपकरण की जरूरत है (ठीक है, तो यह बहुत तेजी से आगे बढ़ेगा, और बाइनरी फाइलें और ऐसा कर सकता है ...) मुझे यह मेरे OpenWRT राउटर पर मिला ...

replace_value=$(echo $replace_value | sed -f /usr/lib/ddns/url_escape.sed)

जहाँ url_escape.sed एक फ़ाइल थी जिसमें ये नियम शामिल थे:

# sed url escaping
s:%:%25:g
s: :%20:g
s:<:%3C:g
s:>:%3E:g
s:#:%23:g
s:{:%7B:g
s:}:%7D:g
s:|:%7C:g
s:\\:%5C:g
s:\^:%5E:g
s:~:%7E:g
s:\[:%5B:g
s:\]:%5D:g
s:`:%60:g
s:;:%3B:g
s:/:%2F:g
s:?:%3F:g
s^:^%3A^g
s:@:%40:g
s:=:%3D:g
s:&:%26:g
s:\$:%24:g
s:\!:%21:g
s:\*:%2A:g

4
दुर्भाग्य से, यह स्क्रिप्ट कुछ वर्णों, जैसे 'é' और ',', 'ई% FFFFFFFFFFFFFFCC' और '% FFFFFFFFFFFFFFC2', क्रमशः (प्रति वर्ण लूप की b / c, मुझे विश्वास है) को विफल करती है।
मैथेमेटिक्स

1
यह बाश 4.3.11 (1) में मेरे लिए काम करने में विफल रहता है। स्ट्रिंग Jogging «à l'Hèze»उत्पन्न करता है Jogging%20%abà%20l%27Hèze%bbकि जे एस को खिलाने के नहीं किया जा सकता decodeURIComponent:(
dmcontador

2
कोड के उस पहले ब्लॉक में प्रिंटफ का अंतिम पैरामीटर क्या है? अर्थात्, यह दोहरे-उद्धरण, एकल-उद्धरण, डॉलर-चिन्ह, पत्र-सी, डबल-उद्धरण क्यों है? एकल-उद्धरण क्या करता है?
कॉलिन फ्राइज़र

1
@dmcontador - यह केवल एक विनम्र बैश स्क्रिप्ट है, इसमें मल्टी-बाइट पात्रों, या यूनिकोड की कोई अवधारणा नहीं है। जब यह ń ( \u0144) की तरह एक चरित्र को देखेगा तो यह भोली-भांति% 144 होगा, \u2561) ( ) 2561% के रूप में आउटपुट होगा। इनके लिए सही रॉरलेंकोडेड उत्तर क्रमशः % C5% 84% 0A और% E2% 95% A1 होगा।
Orwellophile

1
@ColinFraizer एकल उद्धरण निम्नलिखित वर्ण को उसके संख्यात्मक मान में बदलने का कार्य करता है। संदर्भ। pubs.opengroup.org/onlinepubs/9699919799/utilities/…
सैम

94

अपनी बैश स्क्रिप्ट की दूसरी पंक्ति में पर्ल के URI::Escapeमॉड्यूल और uri_escapeफ़ंक्शन का उपयोग करें :

...

value="$(perl -MURI::Escape -e 'print uri_escape($ARGV[0]);' "$2")"
...

संपादित करें: समस्याओं के समाधान को उद्धृत करें , जैसा कि टिप्पणियों में क्रिस जॉन्सन ने सुझाया है। धन्यवाद!


2
URI :: एस्केप स्थापित नहीं हो सकता है, उस मामले में मेरे उत्तर की जांच करें।
blueyed

मैंने इसे (उपयोग echo, पाइप और <>) तय किया , और अब यह तब भी काम करता है जब $ 2 में एक एपॉस्ट्रॉफी या दोहरे उद्धरण शामिल हैं। धन्यवाद!
dubek

9
आप दूर echoभी करते हैं:value="$(perl -MURI::Escape -e 'print uri_escape($ARGV[0]);' "$2")"
क्रिस जॉन्सन

1
क्रिस जॉन्सन का संस्करण बेहतर है। मेरे पास मेरी परीक्षण अभिव्यक्ति में $ {True} था और इसे इको के माध्यम से उपयोग करके uri_escape / Perl वैरिएबल एक्सपेंशन को ट्रिप किया गया।
mm2001

1
@ jrw32982 हाँ, इसे वापस देख, एक और भाषा है जिसके साथ इस कार्य को पूरा करना अच्छा है। अगर मैं कर सकता, मैं अपने downvote वापस लेने चाहते हैं, लेकिन अफसोस यह वर्तमान में बंद है।
thecoshman

69

एक अन्य विकल्प का उपयोग करना है jq(एक फिल्टर के रूप में):

jq -sRr @uri

-R( --raw-input) इनपुट लाइनों को स्ट्रिंग के रूप में मानते हैं, उन्हें JSON के रूप में पार्स करने के बजाय और -sR( --slurp --raw-input) इनपुट को एक स्ट्रिंग में पढ़ता है। -r(--raw-output ) JSON स्ट्रिंग शाब्दिक के बजाय स्ट्रिंग्स की सामग्री को आउटपुट करता है।

यदि इनपुट दूसरे कमांड का आउटपुट नहीं है, तो आप इसे jqस्ट्रिंग चर में स्टोर कर सकते हैं :

jq -nr --arg v "my shell string" '$v|@uri'

-n( --null-input) इनपुट और --arg name valueस्टोर को नहीं पढ़ता हैvaluename एक स्ट्रिंग के रूप में चर में करता है। फ़िल्टर में, $name(एकल उद्धरण में, शेल द्वारा विस्तार से बचने के लिए), चर का संदर्भ देता हैname

बैश फ़ंक्शन के रूप में लिपटे, यह बन जाता है:

function uriencode { jq -nr --arg v "$1" '$v|@uri'; }

या यह प्रतिशत सभी बाइट्स को एनकोड करता है:

xxd -p|tr -d \\n|sed 's/../%&/g'

3
<3 यह ... शीर्ष होना चाहिए और स्वीकार किया जाना चाहिए IMO (हाँ, यदि आप curlउस कार्य को सांकेतिक शब्दों में बदलना बता सकते हैं और अगर बैश में एक बिलिन है जो स्वीकार्य होगा - लेकिन jqऐसा लगता है कि एक सही फिट थियो की तरह है जो मुझे आराम के स्तर को प्राप्त करने से बहुत दूर है। इस उपकरण)
nhed

5
किसी के लिए भी मेरे जैसी ही बात सोचकर: @uriकुछ चर नहीं है, लेकिन स्ट्रिंग्स को फॉर्मेट करने और भागने के लिए इस्तेमाल किया जाने वाला शाब्दिक jq फ़िल्टर है; देख JQ मैनुअल जानकारी के लिए (क्षमा करें, कोई सीधा लिंक, के लिए खोज करने की जरूरत @uriपृष्ठ पर ...)
एसएससी

xxd संस्करण केवल उसी तरह की चीज़ है जिस तरह से मैं ढूंढ रहा था। यहां तक ​​कि अगर यह थोड़ा गंदा है, तो यह कम है और इसकी कोई निर्भरता नहीं है
रियायन सैंडर्सन

1
यूएल-एनकोड को jq का एक नमूना उपयोग:printf "http://localhost:8082/" | jq -sRr '@uri'
आशुतोष जिंदल

67

संपूर्णता के लिए, कई समाधानों का उपयोग करके sedयाawk वर्णों केवल एक विशेष सेट का अनुवाद करते हैं और इसलिए कोड आकार से काफी बड़े होते हैं और अन्य विशेष वर्णों का भी अनुवाद नहीं करते हैं जिन्हें एन्कोड किया जाना चाहिए।

urlencode के लिए एक सुरक्षित तरीका बस हर एक बाइट को एनकोड करना होगा - यहां तक ​​कि जिन्हें अनुमति दी गई होगी।

echo -ne 'some random\nbytes' | xxd -plain | tr -d '\n' | sed 's/\(..\)/%\1/g'

xxd यहाँ इस बात का ध्यान रख रहा है कि इनपुट को बाइट्स के रूप में संभाला जाए न कि पात्रों को।

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

xxd डेबियन में विम-आम पैकेज के साथ आता है और मैं सिर्फ एक सिस्टम पर था जहां यह स्थापित नहीं था और मैं इसे स्थापित नहीं करना चाहता था। अलौकिक hexdumpडेबियन में bsdmainutils पैकेज से उपयोग करना है। निम्नलिखित ग्राफ के अनुसार, bsdmainutils और vim-common में स्थापित होने की समान संभावना होनी चाहिए:

http://qa.debian.org/popcon-png.php?packages=vim-common%2Cbsdmainutils&show_installed=1&want_legend=1&want_ticks=1

लेकिन फिर भी यहाँ एक संस्करण है जो hexdumpइसके बजाय उपयोग करता है xxdऔर trकॉल से बचने की अनुमति देता है :

echo -ne 'some random\nbytes' | hexdump -v -e '/1 "%02x"' | sed 's/\(..\)/%\1/g'

1
xxd -plainबाद होना चाहिए tr -d '\n'!
qdii

3
@qdii क्यों? यह न केवल नए लिंक को urlencode करने के लिए असंभव बना देगा, बल्कि यह xxd द्वारा बनाए गए नए समाचारों को आउटपुट में गलत रूप से सम्मिलित करेगा।
जॉस

1
@josch। यह सीधे तौर पर गलत है। सबसे पहले, किसी भी \nवर्ण xxd -plainमें अनुवाद किया जाएगा 0a। इसके लिए मेरा शब्द न लें, इसे स्वयं आज़माएँ: echo -n -e '\n' | xxd -plainयह साबित करता है कि आपका tr -d '\n'यहाँ बेकार है क्योंकि दूसरा \nहोने के बाद कोई भी नहीं हो सकता है xxd -plain, चरित्र स्ट्रिंग के अंत में echo foobarअपना खुद का \nचरित्र जोड़ता है , इसलिए अपेक्षा के xxd -plainसाथ नहीं खिलाया foobarजाता है foobar\n। इसके बाद xxd -plain इसे कुछ कैरेक्टर स्ट्रिंग में तब्दील 0aकर दिया जाता है, जो इसे उपयोगकर्ता के लिए अनुपयुक्त बना देता है। आप इसे हल -nकरने के echoलिए जोड़ सकते हैं ।
qdii

6
@qdii वास्तव में-गूंज के लिए गायब था, लेकिन xxdकॉल कॉल के सामने आता है tr -d। यह वहाँ है ताकि किसी भी newline foobarद्वारा अनुवादित है xxdtr -dके बाद xxdकॉल नई-पंक्तियों को हटाने के लिए कि XXD उत्पादन होता है। ऐसा लगता है कि आपके पास लंबे समय से फोब्बर कभी नहीं हुआ है, जिससे xxdनई सुर्खियों का निर्माण होता है लेकिन लंबे इनपुट के लिए यह होगा। अतः tr -dआवश्यक है। आपकी धारणा के विपरीत tr -d, इनपुट से नई xxdआउटपुट को निकालने के लिए नहीं बल्कि आउटपुट से था। मैं इनपुट में newlines रखना चाहता हूं। आपका एकमात्र मान्य बिंदु यह है कि गूंज एक अनावश्यक न्यूलाइन जोड़ता है।
जोस

1
@qdii और कोई अपराध लिया - मुझे लगता है कि आप गलत हैं, के अलावा echo -nजो मैं वास्तव में याद आ रही थी
josch

62

एक प्रकार का, बदसूरत, लेकिन सरल हो सकता है:

urlencode() {
    local data
    if [[ $# != 1 ]]; then
        echo "Usage: $0 string-to-urlencode"
        return 1
    fi
    data="$(curl -s -o /dev/null -w %{url_effective} --get --data-urlencode "$1" "")"
    if [[ $? != 3 ]]; then
        echo "Unexpected error" 1>&2
        return 2
    fi
    echo "${data##/?}"
    return 0
}

यहाँ उदाहरण के लिए वन-लाइनर संस्करण है (जैसा कि ब्रूनो द्वारा सुझाया गया है ):

date | curl -Gso /dev/null -w %{url_effective} --data-urlencode @- "" | cut -c 3-

# If you experience the trailing %0A, use
date | curl -Gso /dev/null -w %{url_effective} --data-urlencode @- "" | sed -E 's/..(.*).../\1/'

1
मुझे लगता है कि यह cURL के URL एन्कोडिंग का पुन: उपयोग करने का एक बहुत ही चतुर तरीका है।
ठोस

13
यह बिल्कुल शानदार है! मैं वास्तव में चाहता हूं कि आपने इसे एक पंक्ति छोड़ दिया था ताकि लोग देख सकें कि यह वास्तव में कितना सरल है। URL के लिए dateकमांड का परिणाम सांकेतिक शब्दों में बदलना ... date | curl -Gso /dev/null -w %{url_effective} --data-urlencode @- "" | cut -c 3-(आपको cutपहले 2 वर्णों को बंद करना होगा, क्योंकि कर्ल का आउटपुट तकनीकी रूप से एक क्वेरी स्ट्रिंग के साथ एक सापेक्ष URL है।)
ब्रूनो ब्रोंस्की

2
@BrunoBronosky आपका वन-लाइनर संस्करण अच्छा है, लेकिन एन्कोडिंग के अंत में "% 0A" जोड़ता है। उपयोगकर्ता सावधान रहें। फ़ंक्शन संस्करण में यह समस्या नहीं है।
लेविग्रोकर

7
%0Aअंत में बचने के लिए, के printfबजाय का उपयोग करें echo
kenorb

2
एक लाइनर शानदार है
स्टीफन ब्लम

49

मुझे यह अजगर में अधिक पठनीय लगता है:

encoded_value=$(python -c "import urllib; print urllib.quote('''$value''')")

ट्रिपल 'सुनिश्चित करता है कि मूल्य में एकल उद्धरण चोट नहीं पहुंचाएगा। urllib मानक पुस्तकालय में है। यह इस पागल (वास्तविक दुनिया) के लिए परीक्षा का काम करता है:

"http://www.rai.it/dl/audio/" "1264165523944Ho servito il re d'Inghilterra - Puntata 7

2
मुझे उद्धरणों और ट्रिप्लिकोटिंग के साथ विशेष वर्णों के साथ कुछ परेशानी थी, यह मूल रूप से सब कुछ के लिए काम करने के लिए लग रहा था: एन्कोडेड_वेल्यू = "$ (इको-एन" $ {डेटा} "। अजगर-सी" यूरलिब आयात करें; आयात sys; sys.stdout लिखना (urllib.quote (sys.stdin.read ())) ")";
मोनिका सेलियो

पायथन 3 संस्करण होगा encoded_value=$(python3 -c "import urllib.parse; print (urllib.parse.quote('''$value'''))")
क्रिसल

1
python -c 'import urllib, sys; sys.stdout.writelines(urllib.quote_plus(l, safe="/\n") for l in sys.stdin)'लगभग कोई उद्धृत समस्या नहीं है, और स्मृति / गति कुशल होनी चाहिए (जाँच नहीं की गई है,
स्क्वीटिंग के

2
कोड के रूप में पार्स किए गए स्ट्रिंग में sys.argvप्रतिस्थापित करने के बजाय इसे संदर्भित करना अधिक सुरक्षित होगा $value। क्या होगा अगर valueनिहित ''' + __import__("os").system("rm -rf ~") + '''?
चार्ल्स डफी

2
python -c "import urllib;print urllib.quote(raw_input())" <<< "$data"
रॉकलाईट

30

मैंने निम्नलिखित स्निपेट को प्रोग्राम कॉल की एक श्रृंखला में छड़ी करने के लिए उपयोगी पाया है, जहां URI :: एस्केप स्थापित नहीं हो सकता है:

perl -p -e 's/([^A-Za-z0-9])/sprintf("%%%02X", ord($1))/seg'

( स्रोत )


4
मेरे लिए काम किया। मैंने इसे perl -lpe में बदल दिया ... (अक्षर ell)। इसने अनुगामी न्यूलाइन को हटा दिया, जिसकी मुझे अपने उद्देश्यों के लिए आवश्यकता थी।

2
FYI करें, इसका उलटा प्रयोग करने के लिए, perl -pe 's/\%(\w\w)/chr hex $1/ge'(स्रोत: unix.stackexchange.com/questions/159253/… )
श्रीधर

2
विशेष रूप से आपको कौन से वर्णों को एनकोड करना है, इस पर निर्भर करते हुए, आप इसे सरल बना सकते हैं perl -pe 's/(\W)/sprintf("%%%02X", ord($1))/ge'जिससे अक्षर, संख्या और अंडरस्कोर की अनुमति मिलती है, लेकिन बाकी सब कुछ भी।
लूटें

23

यदि आप GETअनुरोध चलाने और शुद्ध कर्ल का उपयोग करना चाहते हैं तो बस जोड़ें--get @ याकूब के समाधान में ।

यहाँ एक उदाहरण है:

curl -v --get --data-urlencode "access_token=$(cat .fb_access_token)" https://graph.facebook.com/me/feed

15

जगा संस्करण के लिए सीधा लिंक: http://www.shelldorado.com/scripts/cmds/urlencode
मैंने इसे सालों तक इस्तेमाल किया और यह एक आकर्षण की तरह काम करता है

:
##########################################################################
# Title      :  urlencode - encode URL data
# Author     :  Heiner Steven (heiner.steven@odn.de)
# Date       :  2000-03-15
# Requires   :  awk
# Categories :  File Conversion, WWW, CGI
# SCCS-Id.   :  @(#) urlencode  1.4 06/10/29
##########################################################################
# Description
#   Encode data according to
#       RFC 1738: "Uniform Resource Locators (URL)" and
#       RFC 1866: "Hypertext Markup Language - 2.0" (HTML)
#
#   This encoding is used i.e. for the MIME type
#   "application/x-www-form-urlencoded"
#
# Notes
#    o  The default behaviour is not to encode the line endings. This
#   may not be what was intended, because the result will be
#   multiple lines of output (which cannot be used in an URL or a
#   HTTP "POST" request). If the desired output should be one
#   line, use the "-l" option.
#
#    o  The "-l" option assumes, that the end-of-line is denoted by
#   the character LF (ASCII 10). This is not true for Windows or
#   Mac systems, where the end of a line is denoted by the two
#   characters CR LF (ASCII 13 10).
#   We use this for symmetry; data processed in the following way:
#       cat | urlencode -l | urldecode -l
#   should (and will) result in the original data
#
#    o  Large lines (or binary files) will break many AWK
#       implementations. If you get the message
#       awk: record `...' too long
#        record number xxx
#   consider using GNU AWK (gawk).
#
#    o  urlencode will always terminate it's output with an EOL
#       character
#
# Thanks to Stefan Brozinski for pointing out a bug related to non-standard
# locales.
#
# See also
#   urldecode
##########################################################################

PN=`basename "$0"`          # Program name
VER='1.4'

: ${AWK=awk}

Usage () {
    echo >&2 "$PN - encode URL data, $VER
usage: $PN [-l] [file ...]
    -l:  encode line endings (result will be one line of output)

The default is to encode each input line on its own."
    exit 1
}

Msg () {
    for MsgLine
    do echo "$PN: $MsgLine" >&2
    done
}

Fatal () { Msg "$@"; exit 1; }

set -- `getopt hl "$@" 2>/dev/null` || Usage
[ $# -lt 1 ] && Usage           # "getopt" detected an error

EncodeEOL=no
while [ $# -gt 0 ]
do
    case "$1" in
        -l) EncodeEOL=yes;;
    --) shift; break;;
    -h) Usage;;
    -*) Usage;;
    *)  break;;         # First file name
    esac
    shift
done

LANG=C  export LANG
$AWK '
    BEGIN {
    # We assume an awk implementation that is just plain dumb.
    # We will convert an character to its ASCII value with the
    # table ord[], and produce two-digit hexadecimal output
    # without the printf("%02X") feature.

    EOL = "%0A"     # "end of line" string (encoded)
    split ("1 2 3 4 5 6 7 8 9 A B C D E F", hextab, " ")
    hextab [0] = 0
    for ( i=1; i<=255; ++i ) ord [ sprintf ("%c", i) "" ] = i + 0
    if ("'"$EncodeEOL"'" == "yes") EncodeEOL = 1; else EncodeEOL = 0
    }
    {
    encoded = ""
    for ( i=1; i<=length ($0); ++i ) {
        c = substr ($0, i, 1)
        if ( c ~ /[a-zA-Z0-9.-]/ ) {
        encoded = encoded c     # safe character
        } else if ( c == " " ) {
        encoded = encoded "+"   # special handling
        } else {
        # unsafe character, encode it as a two-digit hex-number
        lo = ord [c] % 16
        hi = int (ord [c] / 16);
        encoded = encoded "%" hextab [hi] hextab [lo]
        }
    }
    if ( EncodeEOL ) {
        printf ("%s", encoded EOL)
    } else {
        print encoded
    }
    }
    END {
        #if ( EncodeEOL ) print ""
    }
' "$@"

क्या ASCII के बजाय UTF-8 एन्कोडिंग प्राप्त करने के लिए एक सरल भिन्नता है?
avgvstvs

15

यह सबसे अच्छा एक हो सकता है:

after=$(echo -e "$before" | od -An -tx1 | tr ' ' % | xargs printf "%s")

यह मेरे लिए दो परिवर्धन के साथ काम करता है: 1. -e के साथ -n को तर्क के अंत में एक नई रेखा जोड़ने से बचने के लिए और 2. प्रत्येक जोड़े के सामने% डालने के लिए प्रिंटफ़ स्ट्रिंग में '%%' जोड़ें हेक्स अंक।
रोब फागेन

$ आगे के ब्रैकेट में जोड़ने के बाद काम करता है after=$(echo -e ...
रोमन रे्रन नेस्टरोव

1
कृपया बताएं कि यह कैसे काम करता है। odआदेश आम नहीं है।
मार्क स्टोसबर्ग

यह OS X के साथ काम नहीं करता है odक्योंकि यह GNU से भिन्न आउटपुट स्वरूप का उपयोग करता है od। उदाहरण के लिए OS X के साथ और GNU के साथ printf aa|od -An -tx1 -v|tr \ -प्रिंट । आप OS X या GNU के साथ उपयोग कर सकते हैं । एक ही बात करता है, भले ही POSIX में नहीं है, लेकिन है। -----------61--61--------------------------------------------------------od-61-61odod -An -tx1 -v|sed 's/ */ /g;s/ *$//'|tr \ %|tr -d \\nododxxd -p|sed 's/../%&/g'|tr -d \\nxxdod
निस्सतेमा n ’

2
हालांकि यह काम कर सकता है, यह हर एक चरित्र से बच जाता है
चार्ली

11

यहां एक बैश समाधान दिया गया है जो किसी भी बाहरी कार्यक्रम को लागू नहीं करता है:

uriencode() {
  s="${1//'%'/%25}"
  s="${s//' '/%20}"
  s="${s//'"'/%22}"
  s="${s//'#'/%23}"
  s="${s//'$'/%24}"
  s="${s//'&'/%26}"
  s="${s//'+'/%2B}"
  s="${s//','/%2C}"
  s="${s//'/'/%2F}"
  s="${s//':'/%3A}"
  s="${s//';'/%3B}"
  s="${s//'='/%3D}"
  s="${s//'?'/%3F}"
  s="${s//'@'/%40}"
  s="${s//'['/%5B}"
  s="${s//']'/%5D}"
  printf %s "$s"
}

4
यह बैश संस्करणों के बीच भिन्न व्यवहार करता है। RHEL 6.9 पर बैश 4.1.2 है और इसमें सिंगल कोट्स शामिल हैं। जबकि डेबियन 9 और बैश 4.4.12 सिंगल कोट्स के साथ ठीक है। मेरे लिए सिंगल कोट्स को हटाकर दोनों पर काम किया। s = "$ {s // ',' /% 2C}"
muni764

1
मैंने आपकी खोज को प्रतिबिंबित करने के लिए उत्तर अपडेट किया, @ muni764।
davidchambers

बस एक चेतावनी ... यह चरित्र की तरह चीजों को सांकेतिक शब्दों में बदलना नहीं होगाá
diogovk

10
url=$(echo "$1" | sed -e 's/%/%25/g' -e 's/ /%20/g' -e 's/!/%21/g' -e 's/"/%22/g' -e 's/#/%23/g' -e 's/\$/%24/g' -e 's/\&/%26/g' -e 's/'\''/%27/g' -e 's/(/%28/g' -e 's/)/%29/g' -e 's/\*/%2a/g' -e 's/+/%2b/g' -e 's/,/%2c/g' -e 's/-/%2d/g' -e 's/\./%2e/g' -e 's/\//%2f/g' -e 's/:/%3a/g' -e 's/;/%3b/g' -e 's//%3e/g' -e 's/?/%3f/g' -e 's/@/%40/g' -e 's/\[/%5b/g' -e 's/\\/%5c/g' -e 's/\]/%5d/g' -e 's/\^/%5e/g' -e 's/_/%5f/g' -e 's/`/%60/g' -e 's/{/%7b/g' -e 's/|/%7c/g' -e 's/}/%7d/g' -e 's/~/%7e/g')

यह $ 1 के अंदर स्ट्रिंग को एन्कोड करेगा और इसे $ url में आउटपुट करेगा। हालाँकि आपको इसे एक var में नहीं रखना है अगर आप चाहते हैं। BTW ने टैब के लिए सेड को शामिल नहीं किया, सोचा कि यह इसे रिक्त स्थान में बदल देगा


5
मुझे लगता है कि ऐसा करने का अनुशंसित तरीका नहीं है।
कोड़ी ग्रे

2
कृपया अपनी भावना स्पष्ट करें .... क्योंकि मैंने जो काम बताया है और मैंने कई लिपियों में उसका उपयोग किया है, इसलिए मुझे पता है कि यह मेरे द्वारा सूचीबद्ध सभी वर्णों के लिए काम करता है। तो कृपया समझाएं कि कोई मेरे कोड का उपयोग क्यों नहीं करेगा और पर्ल का उपयोग करेगा क्योंकि इसका शीर्षक "बैश स्क्रिप्ट से URLEncode" है, पर्ल स्क्रिप्ट नहीं है।
manoflinux

कभी-कभी मोती के घोल की आवश्यकता नहीं होती है, इसलिए यह काम में आ सकता है
युवल रिमार

3
यह ऐसा करने के लिए अनुशंसित तरीका नहीं है क्योंकि ब्लैकलिस्ट बुरा अभ्यास है, और यह वैसे भी unicode है।
एक्यूवू

यह सबसे अनुकूल समाधान बिल्ली file.txt के साथ संगत था
mrwaim


7

आप में से किसी को एक ऐसे उपाय की तलाश है जिसमें पर्ल की जरूरत न हो, यहां एक है जिसे केवल हेक्सडंप और awk की जरूरत है:

url_encode() {
 [ $# -lt 1 ] && { return; }

 encodedurl="$1";

 # make sure hexdump exists, if not, just give back the url
 [ ! -x "/usr/bin/hexdump" ] && { return; }

 encodedurl=`
   echo $encodedurl | hexdump -v -e '1/1 "%02x\t"' -e '1/1 "%_c\n"' |
   LANG=C awk '
     $1 == "20"                    { printf("%s",   "+"); next } # space becomes plus
     $1 ~  /0[adAD]/               {                      next } # strip newlines
     $2 ~  /^[a-zA-Z0-9.*()\/-]$/  { printf("%s",   $2);  next } # pass through what we can
                                   { printf("%%%s", $1)        } # take hex value of everything else
   '`
}

नेट पर कुछ स्थानों पर एक साथ सिलाई की गई और कुछ स्थानीय परीक्षण और त्रुटि। यह बहुत अच्छा काम करता है!


7

uni2ascii बहुत उपयोगी है:

$ echo -ne '你好世界' | uni2ascii -aJ
%E4%BD%A0%E5%A5%BD%E4%B8%96%E7%95%8C

2
यह ASCII सीमा के अंदर के वर्णों के लिए काम नहीं करता है , जिसे उद्धृत करने की आवश्यकता है, जैसे %और स्थान (जो -sध्वज के साथ अंतिम रूप दिया जा सकता है )
Boldewyn

7

यदि आप पर्ल पर निर्भर नहीं होना चाहते हैं तो आप sed का उपयोग भी कर सकते हैं। यह थोड़ा गड़बड़ है, क्योंकि प्रत्येक चरित्र को व्यक्तिगत रूप से बचना होगा। निम्नलिखित सामग्री के साथ एक फ़ाइल बनाएं और इसे कॉल करेंurlencode.sed

s/%/%25/g
s/ /%20/g
s/ /%09/g
s/!/%21/g
s/"/%22/g
s/#/%23/g
s/\$/%24/g
s/\&/%26/g
s/'\''/%27/g
s/(/%28/g
s/)/%29/g
s/\*/%2a/g
s/+/%2b/g
s/,/%2c/g
s/-/%2d/g
s/\./%2e/g
s/\//%2f/g
s/:/%3a/g
s/;/%3b/g
s//%3e/g
s/?/%3f/g
s/@/%40/g
s/\[/%5b/g
s/\\/%5c/g
s/\]/%5d/g
s/\^/%5e/g
s/_/%5f/g
s/`/%60/g
s/{/%7b/g
s/|/%7c/g
s/}/%7d/g
s/~/%7e/g
s/      /%09/g

इसका उपयोग करने के लिए निम्न कार्य करें।

STR1=$(echo "https://www.example.com/change&$ ^this to?%checkthe@-functionality" | cut -d\? -f1)
STR2=$(echo "https://www.example.com/change&$ ^this to?%checkthe@-functionality" | cut -d\? -f2)
OUT2=$(echo "$STR2" | sed -f urlencode.sed)
echo "$STR1?$OUT2"

यह स्ट्रिंग को एक ऐसे भाग में विभाजित करेगा, जिसे एन्कोडिंग की आवश्यकता है, और जो भाग ठीक है, उस भाग को एन्कोड करें, जिसे इसकी आवश्यकता है, फिर एक साथ वापस टाँके।

आप इसे सुविधा के लिए एक स्क्रिप्ट में रख सकते हैं, हो सकता है कि इसे एनकोड करने के लिए एक पैरामीटर हो, इसे अपने रास्ते पर रखें और फिर आप इसे केवल देख सकते हैं:

urlencode https://www.exxample.com?isThisFun=HellNo

स्रोत


7

आप जावास्क्रिप्ट के encodeURIComponentपर्ल में अनुकरण कर सकते हैं । यहाँ आदेश है:

perl -pe 's/([^a-zA-Z0-9_.!~*()'\''-])/sprintf("%%%02X", ord($1))/ge'

आप इसे बैश उपनाम के रूप में सेट कर सकते हैं .bash_profile:

alias encodeURIComponent='perl -pe '\''s/([^a-zA-Z0-9_.!~*()'\''\'\'''\''-])/sprintf("%%%02X",ord($1))/ge'\'

अब आप इसमें पाइप कर सकते हैं encodeURIComponent:

$ echo -n 'hèllo wôrld!' | encodeURIComponent
h%C3%A8llo%20w%C3%B4rld!

6

यहाँ नोड संस्करण है:

uriencode() {
  node -p "encodeURIComponent('${1//\'/\\\'}')"
}

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

अच्छी बात। यदि हम बश में सभी समस्याग्रस्त पात्रों से बचने की मुसीबत में जा रहे हैं तो हम सीधे प्रतिस्थापन कर सकते हैं और nodeपूरी तरह से बच सकते हैं। मैंने बैश-केवल समाधान पोस्ट किया। :)
davidchambers

1
पृष्ठ पर कहीं और पाया गया यह संस्करण STDIN से मूल्य को पढ़कर उद्धरण के मुद्दे से बचता है:node -p 'encodeURIComponent(require("fs").readFileSync(0))'
मार्क स्टोसबर्ग

6

सवाल यह है कि यह बकवास में करने के बारे में है और अजगर या पर्ल की कोई आवश्यकता नहीं है क्योंकि वास्तव में एक ही कमांड है जो वास्तव में आप क्या चाहते हैं - "urlencode"।

value=$(urlencode "${2}")

यह बहुत बेहतर है, जैसा कि ऊपर दिए गए उत्तर में है, उदाहरण के लिए, सभी वर्णों को सही ढंग से एनकोड नहीं करता है। Word से प्राप्त होने वाले लंबे डैश के साथ इसे आज़माएँ और आपको गलत एन्कोडिंग प्राप्त होगी।

ध्यान दें, आपको इस आदेश को प्रदान करने के लिए "ग्रिडसाइट-क्लाइंट" स्थापित करने की आवश्यकता है।


1
मेरे bash का संस्करण (GNU 3.2) नहीं है urlencode। आप कौन सा संस्करण उपयोग कर रहे हैं?
श्रीधर सरनोबत

1
मेरे पास 4.3.42 है, लेकिन urlencode कमांड "ग्रिडसाइट-क्लाइंट" द्वारा प्रदान किया गया है। स्थापित करने का प्रयास करें और आप ठीक होना चाहिए।
डायलन

5
तो आपका उत्तर किसी भी चीज़ से बेहतर नहीं है, जिसके लिए दूसरों को स्थापित करने की आवश्यकता है (अजगर, पर्ल, लुआ, ...)
साइरिल पोंटिविक्स

सिवाय इसके कि इसे केवल एक संपूर्ण भाषा (और पुस्तकालयों) के बजाय एकल उपयोगिता स्थापित करने की आवश्यकता है, प्लस सुपर सरल है और यह देखने के लिए स्पष्ट है कि यह क्या कर रहा है।
डायलन

इस कमांड को प्रदान करने वाले पैकेज / प्रोजेक्ट पेज के लिए एक लिंक पहले उपयोगी होता।
डोरोन बेहार


4

रूबी, पूर्णता के लिए

value="$(ruby -r cgi -e 'puts CGI.escape(ARGV[0])' "$2")"

4

एक और php दृष्टिकोण:

echo "encode me" | php -r "echo urlencode(file_get_contents('php://stdin'));"

2
echoएक नई चरित्र (हेक्स 0xa) को जोड़ देगा । ऐसा करने से रोकने के लिए, का उपयोग करें echo -n
मैथ्यू हॉल

3

यहाँ एक एम्बेडेड सिस्टम के लिए बिजीबॉक्स ऐश शेल के लिए मेरा संस्करण है, मैंने मूल रूप से Orwellophile के संस्करण को अपनाया है:

urlencode()
{
    local S="${1}"
    local encoded=""
    local ch
    local o
    for i in $(seq 0 $((${#S} - 1)) )
    do
        ch=${S:$i:1}
        case "${ch}" in
            [-_.~a-zA-Z0-9]) 
                o="${ch}"
                ;;
            *) 
                o=$(printf '%%%02x' "'$ch")                
                ;;
        esac
        encoded="${encoded}${o}"
    done
    echo ${encoded}
}

urldecode() 
{
    # urldecode <string>
    local url_encoded="${1//+/ }"
    printf '%b' "${url_encoded//%/\\x}"
}

2

यहाँ ऐसा करने के लिए एक POSIX फ़ंक्शन है:

encodeURIComponent() {
  awk 'BEGIN {while (y++ < 125) z[sprintf("%c", y)] = y
  while (y = substr(ARGV[1], ++j, 1))
  q = y ~ /[[:alnum:]_.!~*\47()-]/ ? q y : q sprintf("%%%02X", z[y])
  print q}' "$1"
}

उदाहरण:

value=$(encodeURIComponent "$2")

स्रोत


2

यहाँ Lua का उपयोग करते हुए एक-पंक्ति रूपांतरण है, जो सभी RFC 3986 अनारक्षित वर्णों को छोड़कर ब्लूएड के उत्तर के समान है (बिना इस उत्तर के )

url=$(echo 'print((arg[1]:gsub("([^%w%-%.%_%~])",function(c)return("%%%02X"):format(c:byte())end)))' | lua - "$1")

इसके अतिरिक्त, आपको यह सुनिश्चित करने की आवश्यकता हो सकती है कि आपके स्ट्रिंग में नई लाइनें LF से CRLF में परिवर्तित हो गई हैं, जिस स्थिति में आप gsub("\r?\n", "\r\n")प्रतिशत-एन्कोडिंग से पहले श्रृंखला में एक सम्मिलित कर सकते हैं ।

यहां एक ऐसा संस्करण है, जो गैर-मानक शैली में एप्लिकेशन / x-www-form-urlencoded में है , जो उस नईलाइन को सामान्य करता है, साथ ही '% 20' के बजाय '+' के रूप में एन्कोडिंग स्थान (जो संभवतः जोड़ा जा सकता है) एक समान तकनीक का उपयोग करके पर्ल स्निपेट)।

url=$(echo 'print((arg[1]:gsub("\r?\n", "\r\n"):gsub("([^%w%-%.%_%~ ]))",function(c)return("%%%02X"):format(c:byte())end):gsub(" ","+"))' | lua - "$1")

1

Php इंस्टॉल होने के बाद मैं इस तरह से उपयोग करता हूं:

URL_ENCODED_DATA=`php -r "echo urlencode('$DATA');"`

1

यह रॉवेलुरेंकोड और रॉर्लडब्लास्ट फ़ंक्शंस (लिंक: कर्ल कमांड के लिए डेटा urlencode करने के लिए कैसे? ) युक्त ऑरवेलोफाइल के उत्तर का ksh संस्करण है । मेरे पास टिप्पणी पोस्ट करने के लिए पर्याप्त प्रतिनिधि नहीं है, इसलिए नई पोस्ट ।।

#!/bin/ksh93

function rawurlencode
{
    typeset string="${1}"
    typeset strlen=${#string}
    typeset encoded=""

    for (( pos=0 ; pos<strlen ; pos++ )); do
        c=${string:$pos:1}
        case "$c" in
            [-_.~a-zA-Z0-9] ) o="${c}" ;;
            * )               o=$(printf '%%%02x' "'$c")
        esac
        encoded+="${o}"
    done
    print "${encoded}"
}

function rawurldecode
{
    printf $(printf '%b' "${1//%/\\x}")
}

print $(rawurlencode "C++")     # --> C%2b%2b
print $(rawurldecode "C%2b%2b") # --> C++

1

जावास्क्रिप्ट से बेहतर URL क्या होगा?

node -p "encodeURIComponent('$url')"

ऑप प्रश्न के दायरे से बाहर। न बैश, न कर्ल। भले ही मुझे यकीन है कि नोड उपलब्ध होने पर बहुत अच्छा काम करता है।
साइरिल पोंटवीक्स

क्यों इस पर वोटिंग हुई और न कि अजगर / पर्ल के जवाब? इसके अलावा यह कैसे मूल प्रश्न का जवाब नहीं देता है "कर्ल कमांड के लिए डेटा को कैसे urlencode करें?"। इसका उपयोग बैश स्क्रिप्ट से किया जा सकता है और परिणाम कर्ल कमांड को दिया जा सकता है।
नेस्टर

मैंने दूसरों को भी वोट दिया। सवाल यह था कि इसे बैश स्क्रिप्ट में कैसे किया जाए। यदि किसी अन्य भाषा का उपयोग नोड / जेएस, अजगर या पर्ल की तरह किया जाता है, तो सीधे कर्ल का उपयोग करने की आवश्यकता नहीं है।
Cyrille Pontvieux

2
हालांकि, मैं इस समस्या से निपटने के लिए परेशान नहीं हुआ, लेकिन यह है कि जावास्क्रिप्ट में उपयोग के लिए डेटा को ठीक से बचाना आवश्यक है। जैसे सिंगल कोट्स और कुछ बैकलैश पागलपन के साथ इसे आज़माएं। यदि आप नोड का उपयोग करना चाहते हैं, तो आप स्टड से सामान को बेहतर तरीके से पढ़ सकते हैंnode -p 'encodeURIComponent(require("fs").readFileSync(0))'
स्टड

1
यदि आप STDIN से डेटा पाइप कर रहे हैं, तो @ MichaelKrelin-hacker के समाधान से सावधान रहें, यह सुनिश्चित करें कि एक अनुगामी रूपरेखा शामिल न करें। उदाहरण के लिए, echo | ...गलत है, जबकि echo -n | ...न्यूलाइन को दबाता है।
मार्क स्टोसबर्ग

0

निम्नलिखित Orwellophile के उत्तर पर आधारित है, लेकिन LC_ALL = C (vte.sh से एक चाल) सेट करके टिप्पणियों में उल्लिखित मल्टीबाइट बग को हल करता है। मैंने इसे फ़ंक्शन उपयुक्त PROMPT_COMMAND के रूप में लिखा है, क्योंकि मैं इसका उपयोग करता हूं।

print_path_url() {
  local LC_ALL=C
  local string="$PWD"
  local strlen=${#string}
  local encoded=""
  local pos c o

  for (( pos=0 ; pos<strlen ; pos++ )); do
     c=${string:$pos:1}
     case "$c" in
        [-_.~a-zA-Z0-9/] ) o="${c}" ;;
        * )               printf -v o '%%%02x' "'$c"
     esac
     encoded+="${o}"
  done
  printf "\033]7;file://%s%s\007" "${HOSTNAME:-}" "${encoded}"
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.