Curl komutu için veri urlencode nasıl?


319

Bir parametre alır ve kıvrılma yoluyla web sitesine gönderir test için bir bash komut dosyası yazmaya çalışıyorum. Özel karakterler düzgün işlendiğinden emin olmak için değeri kodlamak gerekir. Bunu yapmanın en iyi yolu nedir?

İşte benim temel komut dosyası:

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

Ayrıca bkz: URL kodlu dizenin kabuğunda kodu nasıl çözülür? kıvrılmayan çözümler için.
kenorb

Yanıtlar:


396

Kullanın curl --data-urlencode; from man curl:

Bu, --dataURL kodlaması gerçekleştirmesi dışında diğer seçeneklere benzer veriler yayınlar . CGI uyumlu <data>olması için, bölüm bir ad ve ardından bir ayırıcı ve bir içerik belirtimi ile başlamalıdır.

Örnek kullanım:

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

Daha fazla bilgi için kılavuz sayfasına bakınız .

Bu, 7.18.0 veya daha yeni bir kıvrımı gerektirir (Ocak 2008'de yayınlandı) . curl -VHangi sürüme sahip olduğunuzu kontrol etmek için kullanın .

Sorgu dizesini de kodlayabilirsiniz :

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
Sadece http POST için çalışıyor gibi görünüyor. Buradaki belgeler: curl.haxx.se/docs/manpage.html#--data-urlencode
Stan James

82
@StanJames Eğer böyle kullanırsanız curl bir GET isteği için kodlama da yapabilir. curl -G --data-urlencode "blah=df ssdf sdf" --data-urlencode "blah2=dfsdf sdfsd " http://whatever.com/whatever
kberg

13
@kberg aslında, bu yalnızca sorgu verileri için çalışır. curl '?' ardından urlen kodlanmış parametreler. Bazı url postfix'lerini (bazı belge kimlikleri için CouchDB GET gibi) urlencode etmek istiyorsanız, '--data-urlencode' çalışmaz.
Bokeh

1
Çalışmıyor curl --data-urlencode "description=![image]($url)" www.example.com. Neden olduğu hakkında bir fikrin var mı? ``
Khurshid Alam

1
@NadavB Kaçış "
BlackJack

179

İşte saf BASH cevabı.

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
}

İki şekilde kullanabilirsiniz:

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

[Düzenlenmiş]

İşte tüm alçakgönüllülükle - harika olan eşleşen rawurldecode () işlevi.

# 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
}

Eşleşen set ile artık bazı basit testler yapabiliriz:

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

Output: Matched

Ve gerçekten harici bir araca ihtiyacınız olduğunu düşünüyorsanız (iyi, çok daha hızlı gidecek ve ikili dosyalar ve benzeri şeyler yapabilir ...) Bunu OpenWRT yönlendiricimde buldum ...

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

Url_escape.sed, şu kuralları içeren bir dosyaydı:

# 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
Ne yazık ki, bu komut dosyası 'é' ve '½' gibi bazı karakterlerde başarısız olur ve sırasıyla 'e% FFFFFFFFFFFFFFCC' ve '% FFFFFFFFFFFFFFC2' çıktılarını verir (sanırım karakter başına döngüden b / c).
Matthemattics

1
Bash 4.3.11 (1) 'de benim için çalışmıyor. Dize JS :(Jogging «à l'Hèze»Jogging%20%abà%20l%27Hèze%bbdecodeURIComponent
dmcontador

2
Bu ilk kod bloğunda printf için son parametre ne anlama geliyor? Yani, neden çift tırnak, tek tırnak, dolar işareti, harf-c, çift tırnak? Tek alıntı yapıyor mu?
Colin Fraizer

1
@dmcontador - sadece mütevazi bir bash betiği, çok baytlı karakterler veya unicode kavramları yok. \u0144Ń ( \u2561) gibi bir karakter gördüğünde naif olarak% 144, ╡ ( ) çıktısı% 2561 olur. Bunlar için doğru ham kodlanmış cevaplar sırasıyla% C5% 84% 0A ve% E2% 95% A1 olacaktır.
Orwellophile

1
@ColinFraizer tek tırnak, aşağıdaki karakteri sayısal değerine dönüştürmeye yarar. ref. pubs.opengroup.org/onlinepubs/9699919799/utilities/…
Sam

94

Perl URI::Escapemodülünü ve uri_escapeişlevini bash betiğinizin ikinci satırında kullanın :

...

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

Düzenleme: Yorumlarda Chris Johnsen tarafından önerildiği gibi alıntı sorunlarını düzeltin. Teşekkürler!


2
URI :: Escape kurulu olmayabilir, bu durumda cevabımı kontrol edin.
blueyed

Bu (kullanım echo, boru ve <>) düzeltildi ve şimdi $ 2 kesme işareti veya çift tırnak içerdiğinde bile çalışıyor. Teşekkürler!
dubek

9
Sen de echovalue="$(perl -MURI::Escape -e 'print uri_escape($ARGV[0]);' "$2")"
yoksun

1
Chris Johnsen'in versiyonu daha iyi. Test ifademde $ {True} vardı ve echo aracılığıyla bunu kullanarak uri_escape / Perl değişken genişletme açıldı.
mm2001

1
@ jrw32982 evet, geriye bakmak, bu görevi yerine getirmek için başka bir dile sahip olmak iyi. Eğer yapabilseydim, geri oyumu geri alırdım, ama ne yazık ki şu anda kilitli.
thecoshman

69

Başka bir seçenek de jq(filtre olarak) kullanmaktır:

jq -sRr @uri

-R( --raw-input) girdi satırlarını JSON olarak ayrıştırmak yerine dize olarak ele alır ve -sR( --slurp --raw-input) girdiyi tek bir dize olarak okur. -r( --raw-output), dizelerin içeriğini JSON dize değişmez değerleri yerine çıktılar.

Giriş başka bir komutun çıktısı değilse, onu bir jqdize değişkeninde saklayabilirsiniz :

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

-n( --null-input) girdiyi okumaz ve değişkeni dize olarak --arg name valuesaklar . Filtrede, (tek tırnak içinde, kabuk tarafından genişlemeyi önlemek için), değişkene başvurur .valuename$namename

Bash işlevi olarak sarıldığında, bu olur:

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

Veya bu yüzde, tüm baytları kodlar:

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

3
<3 o ... üst ve kabul edilmiş IMO olmalıdır (evet eğer curlişe yarayan kodlamayı söyleyebilirseniz ve bash kabul edilebilir bir yerleşik varsa - ama jqkonfor seviyesine ulaşmaktan çok uzaktayım bu araç)
nhed

5
benimle aynı şeyi merak eden herkes için: @uribazı değişken değil, dizeleri biçimlendirmek ve kaçmak için kullanılan gerçek bir jq filtresi; bkz manuel jq ayrıntılar için (pardon, doğrudan bir bağlantı, aranacak gerek @urisayfasında ...)
ssc

xxd sürümü sadece aradığım şey. Biraz kirli olsa bile, kısa ve bağımlılıkları yok
Rian Sanderson

1
URL kodlaması için jq örnek kullanımı:printf "http://localhost:8082/" | jq -sRr '@uri'
Ashutosh Jindal

67

tamlık uğruna, özel bir karakter kümesini kullanan sedveya awkyalnızca çeviren birçok çözüm ve dolayısıyla kod boyutuna göre oldukça büyüktür ve ayrıca kodlanması gereken diğer özel karakterleri de çevirmez.

urlencode için güvenli bir yol, her bir baytı kodlamaktır - izin verilenler bile.

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

xxd burada girdinin karakter değil bayt olarak işlenmesine dikkat ediyor.

Düzenle:

xxd Debian'da vim-ortak paket ile geliyor ve ben sadece yüklü olmadığı bir sistemdeydim ve yüklemek istemedim. Alternatif, hexdumpDebian'daki bsdmainutils paketinden kullanmaktır . Aşağıdaki grafiğe göre, bsdmainutils ve vim-common, takılma olasılığı yaklaşık olarak eşit olmalıdır:

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

ancak yine de burada çağrı hexdumpyerine kullanılan xxdve trçağrıyı önlemeye izin veren bir sürüm :

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

1
xxd -plainSONRASI olmalı tr -d '\n'!
qdii

3
@qdii neden? bu sadece yeni satırların urlencode edilmesini imkansız hale getirmekle kalmaz, aynı zamanda xxd tarafından oluşturulan yeni satırları da çıkışa yanlış ekler.
josch

1
@josch. Bu sadece yanlış. İlk olarak, herhangi bir \nkarakter tarafından xxd -plainçevrilecektir 0a. Bunun için söz almayın, kendiniz deneyin: echo -n -e '\n' | xxd -plainBu senin kanıtlıyor tr -d '\n'herhangi olamaz burada işe yaramaz \nsonra xxd -plain , Second echo foobarkendi ekler \nkarakter dizesinin sonunda karakterini, yani xxd -plainile beslenen değil foobarama beklendiği gibi foobar\n. daha sonra xxd -plain onu biten bir karakter dizesine çevirerek 0akullanıcı için uygun değildir. Sen ekleyebilir -niçin echobunu çözmek için.
qdii

6
@qdii gerçekten -n yankı için eksikti ama xxdçağrı çağrının önünde tr -d. Orada ait olduğu için herhangi bir satırsonu foobartarafından çevrilir xxd. tr -dSonra xxdçağrı XXD ürettiğini yeni satır kaldırmaktır. Görünüşe göre asla yeterince uzun foobarınız yok, böylece xxdyeni satırlar üretiyor, ancak uzun girdiler için olacak. Yani tr -dgerekli. Varsayımınızın aksine, tr -dyeni satırları girişten değil xxdçıktıdan çıkarmak oldu . Yeni satırları girdide tutmak istiyorum. Tek geçerli noktanız, yankı gereksiz bir satırsonu ekliyor.
josch

1
@qdii ve hiçbir suç alınmadı - Ben echo -ngerçekten yanlış olduğunu düşünüyorum , gerçekten eksik olan dışında
josch

62

Varyantlardan biri çirkin ama basit olabilir:

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
}

Örneğin, tek katmanlı versiyon ( Bruno tarafından önerildiği gibi ):

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
Bu cURL URL kodlamasını yeniden kullanmak için çok akıllıca bir yol olduğunu düşünüyorum.
solidsnack

13
Bu kesinlikle harika! İnsanların ne kadar basit olduğunu görebilmeleri için bir satır bırakmış olmanızı dilerim. URL, datekomutun sonucunu kodlamak için … date | curl -Gso /dev/null -w %{url_effective} --data-urlencode @- "" | cut -c 3-( cutİlk 2 karakter kapalı olmalıdır, çünkü curl çıktısı teknik olarak sorgu dizesi olan göreceli bir URL'dir.)
Bruno Bronosky

2
@BrunoBronosky Tek satırlı varyantınız iyi ancak görünüşte kodlamanın sonuna bir "% 0A" ekliyor. Kullanıcılar sakının. İşlev sürümünde bu sorun yok gibi görünüyor.
levigroker

7
%0ASonunda önlemek için printfyerine kullanın echo.
kenorb

2
bir astar harika
Stephen Blum

49

Python'da daha okunabilir buluyorum:

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

üçlü 'değerdeki tek tırnakların zarar görmemesini sağlar. urllib standart kütüphanede. Bu çılgın (gerçek dünya) url için örnek için çalışır:

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

2
Üçlü tırnak ve tırnak ile bazı sorunlar vardı, bu temelde her şey için işe yaramış gibi görünüyordu: encoded_value = "$ (echo -n" $ {data} "| python -c" import urllib; import sys; sys.stdout. write (urllib.quote (sys.stdin.read ())) ")";
Slandering Monica Cellio'yu durdur

Python 3 sürümü olurdu encoded_value=$(python3 -c "import urllib.parse; print (urllib.parse.quote('''$value'''))").
Creshal

1
python -c 'import urllib, sys; sys.stdout.writelines(urllib.quote_plus(l, safe="/\n") for l in sys.stdin)'neredeyse hiç alıntı problemi yok ve bellek / hız verimli olmalı (kontrol edilmedi, gözlerini kısarak sakla)
Alois Mahdal

2
Daha sonra kod olarak ayrıştırılan bir dizginin sys.argvyerine geçmek yerine atıfta bulunmak çok daha güvenli olacaktır $value. Ne olursa valueiçeriyordu ''' + __import__("os").system("rm -rf ~") + '''?
Charles Duffy

2
python -c "import urllib;print urllib.quote(raw_input())" <<< "$data"
Rockallite

30

Aşağıdaki snippet'i, URI :: Escape yüklü olmayabilecek bir program çağrıları zincirine yapıştırmak için yararlı buldum:

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

( kaynak )


4
benim için çalıştı. Bunu perl -lpe olarak değiştirdim ... (ell harfi). Bu, benim amacım için gerekli olan sondaki yeni satırı kaldırdı.
JohnnyLambada

2
FYI, bunun tersini yapmak için kullanın perl -pe 's/\%(\w\w)/chr hex $1/ge'(kaynak: unix.stackexchange.com/questions/159253/… )
Sridhar Sarnobat

2
Özel olarak hangi karakterleri kodlamanız gerektiğine bağlı olarak perl -pe 's/(\W)/sprintf("%%%02X", ord($1))/ge', harflere, sayılara ve alt çizgilere izin veren, ancak diğer her şeyi kodlayanlara basitleştirebilirsiniz .
robru

23

GETİsteği çalıştırmak ve saf kıvırmak istiyorsanız --get@ Jacob'un çözümüne ekleyin .

İşte bir örnek:

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

15

Awk sürümüne doğrudan bağlantı: http://www.shelldorado.com/scripts/cmds/urlencode
Yıllarca kullandım ve bir cazibe gibi çalışıyor

:
##########################################################################
# 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 yerine UTF-8 kodlaması almak için basit bir varyasyon var mı?
avgvstvs

15

Bu en iyisi olabilir:

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

Bu benim için iki ekleme ile çalışır: 1. bağımsız değişkenin sonuna bir satırsonu eklemek için -e yerine -n ​​yazın ve 2. her bir çiftin önüne% koymak için printf dizesine '%%' ekleyin onaltılık basamak.
Rob Fagen

$ önde dirsek eklemek sonra çalışır after=$(echo -e ...
Roman Rhrn Nesterov

1
Lütfen bunun nasıl çalıştığını açıklayın. odKomut yaygın değildir.
Mark Stosberg

odGNU'dan farklı bir çıkış biçimi kullandığından OS X'lerle çalışmaz od. Örneğin OS X'ler ve GNU ile printf aa|od -An -tx1 -v|tr \ -yazdırır . Sen kullanabilirsiniz ya OS X adlı ile veya GNU . POSIX'te olmasa da aynı şeyi yapıyor . -----------61--61--------------------------------------------------------od-61-61odod -An -tx1 -v|sed 's/ */ /g;s/ *$//'|tr \ %|tr -d \\nododxxd -p|sed 's/../%&/g'|tr -d \\nxxdod
nisetama

2
Bu işe yarasa da, her bir karakterden kaçar
Charlie

11

İşte herhangi bir harici programı çağırmayan bir Bash çözümü:

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
Bu, bash sürümleri arasında farklı davranır. RHEL 6.9'da bash 4.1.2'dir ve tek tırnakları içerir. Debian 9 ve bash 4.4.12 tek tırnak işaretleri ile iyidir. Benim için tek tırnak kaldırmak her ikisinde de işe yaradı. s = "$ {s // ',' /% 2C}"
muni764

1
Cevabı bulmanızı yansıtacak şekilde güncelledim, @ muni764.
davidchambers

Sadece bir uyarı ... bu karakter gibi şeyleri kodlamayacaká
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')

bu, $ 1 içindeki dizeyi kodlar ve $ url olarak verir. Eğer isterseniz bir var koymak zorunda değilsiniz. BTW sekme için sed içermedi, boşluklara dönüşeceğini düşündü


5
Bunun bunu yapmanın önerilen yolu olmadığını hissediyorum .
Cody Gray

2
duygularını açıkla lütfen .... çünkü ben söyledim ne çalışır ve ben birkaç komut dosyalarında kullandım bu yüzden listelediğim tüm chars için çalışır biliyorum. Bu yüzden lütfen neden birisinin kodumu kullanmadığını açıklayın ve bunun başlığı perl komut dosyası değil, "bash komut dosyasından URLEncode" olduğundan perl kullanın.
manoflinux

bazen işe
yaramayacak bir

3
Bu, bunu yapmak için önerilen yol değildir çünkü kara liste kötü bir uygulamadır ve bu zaten unicode düşmancadır.
Ekevoo

Bu cat file.txt ile uyumlu en kolay çözümdü
mrwaim


7

Perl'e ihtiyaç duymayan bir çözüm arayanlarınız için, burada sadece hexdump ve awk'ye ihtiyaç duyan bir çözüm var:

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
   '`
}

Net ve bazı yerel deneme yanılma birkaç yerden birlikte dikişli. Harika çalışıyor!


7

uni2ascii çok kullanışlıdır:

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

2
Bu , ASCII aralığı içindeki , tırnak işareti, %boşluk ve boşluk gerektiren karakterler için işe yaramaz (sonuncusu -sbayrakla düzeltilebilir )
Boldewyn

7

Perl'e bağımlı olmak istemiyorsanız sed'i de kullanabilirsiniz. Her karakterin ayrı ayrı kaçması gerektiği için biraz dağınık. Aşağıdaki içeriklere sahip bir dosya oluşturun ve arayınurlencode.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

Kullanmak için aşağıdakileri yapın.

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"

Bu, dizeyi kodlamaya ihtiyaç duyan bir parçaya böler ve iyi olan kısım, ona ihtiyaç duyan parçayı kodlar, sonra tekrar birleştirir.

Kolaylık sağlamak için bir sh komut dosyasına koyabilirsiniz, belki de kodlamak için bir parametre almasını sağlayın, yolunuza koyun ve sonra sadece şunu arayabilirsiniz:

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

kaynak


7

Javascript'leri encodeURIComponentperl'de taklit edebilirsiniz . İşte komut:

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

Bunu bash takma adı olarak ayarlayabilirsiniz .bash_profile:

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

Şimdi içine boru yapabilirsiniz encodeURIComponent:

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

6

Düğüm sürümü şöyledir:

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

1
Dizede, tek bir ters eğik çizgi veya yeni satırlar gibi tek tırnak işaretleri arasında geçerli olmayan başka karakterler varsa bu mola olmaz mı?
Stuart P. Bentley

İyi bir nokta. Bash'deki tüm sorunlu karakterlerden kaçma sorununa gidecek olursak, değiştirmeleri doğrudan gerçekleştirebilir ve nodetamamen önleyebiliriz . Ben sadece Bash çözümü gönderdim. :)
davidchambers

1
Sayfanın başka bir yerinde bulunan bu varyant, node -p 'encodeURIComponent(require("fs").readFileSync(0))'
STDIN'in

6

Soru, bunu bash'da yapmakla ilgilidir ve aslında tam olarak ne istediğinizi yapan tek bir komut olduğu için python veya perl'e gerek yoktur - "urlencode".

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

Yukarıdaki perl yanıtı, tüm karakterleri doğru şekilde kodlamadığından, bu da çok daha iyidir. Word'den aldığınız uzun çizgi ile deneyin ve yanlış kodlamayı elde edin.

Bu komutu sağlamak için "gridsite-istemcileri" yüklü olmalıdır.


1
Benim bash (GNU 3.2) versiyonumda yok urlencode. Hangi sürümü kullanıyorsunuz?
Sridhar Sarnobat

1
4.3.42 var, ama urlencode komutu "gridsite-istemcileri" tarafından sağlanır. Bunu yüklemeyi deneyin ve iyi olmalısınız.
Dylan

5
Yani cevabınız başkalarının yüklü olmasını gerektiren herhangi birinden daha iyi değil (python, perl, lua,…)
Cyrille Pontvieux

Tüm dil (ve kütüphaneler) yerine yalnızca tek bir yardımcı programın yüklenmesini gerektirmesi dışında, ne yaptığını görmek çok basit ve açıktır.
Dylan

Bu komutu sağlayan paket / proje sayfası için ilk bağlantı faydalı olurdu.
Doron Behar

6

Basit PHP seçeneği:

echo 'part-that-needs-encoding' | php -R 'echo urlencode($argn);'

4

Ruby, bütünlük için

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

4

Başka bir php yaklaşımı:

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

2
echoyeni satır karakteri (hex 0xa) ekleyecektir . Bunu yapmasını durdurmak için kullanın echo -n.
Mathew Hall

3

İşte gömülü bir sistem için meşgul kutusu kül kabuğu için benim sürüm, ben Orwellophile varyantını benimsedi:

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

İşte bunu yapmak için bir POSIX işlevi:

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"
}

Misal:

value=$(encodeURIComponent "$2")

Kaynak


2

İşte Lua kullanan tek satırlık bir dönüşüm, blueyed'in cevabına benzer, ancak tüm RFC 3986 Korunmamış Karakterler kodlanmamış olarak kaldı ( bu cevap gibi ):

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

Ayrıca, dizenizdeki yeni satırların LF'den CRLF'ye dönüştürüldüğünden emin olmanız gerekebilir; bu durumda gsub("\r?\n", "\r\n")yüzde kodlamadan önce zincire a ekleyebilirsiniz .

İşte standart olmayan uygulama stili / x-www-form-urlencoded , bu satırsonu normalleştirmeyi yapan ve boşlukları '% 20' yerine '+' olarak kodlayan (muhtemelen Benzer bir teknik kullanarak perl snippet'i).

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

1

Yüklü php olması bu şekilde kullanın:

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

1

Bu, orwellophile'ın rawurlencode ve rawurldecode işlevlerini içeren yanıtının ksh sürümüdür (link: curl komutu için verileri nasıl urlencode? ). Yorum göndermek için yeterli temsilcim yok, dolayısıyla yeni gönderi ..

#!/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'leri javascript'ten daha iyi ne ayrıştırır?

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

Op soru kapsamı dışında. Bash değil, kıvrılma değil. Eminim bile düğüm varsa çok iyi çalışır.
Cyrille Pontvieux

Python / perl cevaplarını neden vermiyor? Ayrıca, bu orijinal soru "curl komutu için veri urlencode nasıl?" Bu bir bash betiğinden kullanılabilir ve sonuç bir curl komutuna verilebilir.
Nestor Urquiza

Diğerlerini de aşağı seçtim. Soru, bunun bir bash betiğinde nasıl yapılacağıydı. Node / js, python veya perl gibi başka bir dil kullanılıyorsa, doğrudan curl kullanmaya gerek yoktur.
Cyrille Pontvieux

2
Ben aşağı itmek için uğraşmadı, ancak bu komut ile sorun javascript kullanmak için düzgün kaçmak için veri gerektirir olmasıdır. Tek tırnak ve bazı ters eğik delilik ile deneyin. Düğüm kullanmak istiyorsanız, stdin gibi şeyleri okursanız iyi olurnode -p 'encodeURIComponent(require("fs").readFileSync(0))'
Michael Krelin - hacker

1
STDIN'den veri veriyorsanız @ MichaelKrelin-hacker çözümüne dikkat edin. Sondaki satırsonu eklemediğinizden emin olun. Örneğin , satırsonu bastırırken echo | ...yanlıştır echo -n | ....
Mark Stosberg

0

Aşağıdakiler Orwellophile'ın cevabına dayanır, ancak LC_ALL = C (vte.sh'dan bir numara) ayarlayarak yorumlarda belirtilen çok baytlı hatayı çözer. Ben uygun PROMPT_COMMAND işlevi şeklinde yazdım, çünkü ben böyle kullanıyorum.

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}"
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.