Comment faire pour les données urlencode pour la commande curl?
j'essaie d'écrire un script bash pour tester qui prend un paramètre et l'envoie par curl vers le site web. J'ai besoin d'encoder la valeur pour s'assurer que les caractères spéciaux sont correctement traitées. Quelle est la meilleure façon de le faire?
Voici mon script de base:
#!/bin/bash
host=${1:?'bad host'}
value=
shift
shift
curl -v -d "param=${value}" http://${host}/somepath $@
30 réponses
utiliser curl --data-urlencode
; à partir de man curl
:
cette option affiche des données, similaires aux autres options
--data
à l'exception que cela effectue le codage D'URL. Pour être conforme à la norme CGI, la partie<data>
doit commencer par un nom suivi d'un séparateur et d'une spécification de contenu.
exemple d'usage:
curl \
--data-urlencode "paramName=value" \
--data-urlencode "secondParam=value" \
http://example.com
Voir à la page man pour plus d'info.
il faut curl 7.18.0 ou plus récent (janvier 2008) . Utilisez curl -V
pour vérifier quelle version vous avez.
Voici la réponse pure BASH.
rawurlencode() {
local string=""
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
}
Vous pouvez l'utiliser de deux façons:
easier: echo http://url/q?=$( rawurlencode "$args" )
faster: rawurlencode "$args"; echo http://url/q?${REPLY}
[édité]
Voici la fonction rawurldecode() correspondant, qui - avec toute modestie - est impressionnant.
# 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
}
Avec l'ensemble correspondant, nous pouvons maintenant effectuer quelques tests simples:
$ diff rawurlencode.inc.sh \
<( rawurldecode "$( rawurlencode "$( cat rawurlencode.inc.sh )" )" ) \
&& echo Matched
Output: Matched
Et si vraiment vous sentez vraiment que vous avez besoin d'un outil externe (eh bien, aller beaucoup plus vite, et susceptible de faire des fichiers binaires et... J'ai trouvé ça sur mon routeur OpenWRT...
replace_value=$(echo $replace_value | sed -f /usr/lib/ddns/url_escape.sed)
où url_escape.sed était un fichier qui contenait ces règles:
# 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
utilisez le module URI::Escape
et la fonction uri_escape
de Perl dans la deuxième ligne de votre script bash:
...
value="$(perl -MURI::Escape -e 'print uri_escape($ARGV[0]);' "")"
...
modifier: corriger les problèmes de citation, comme suggéré par Chris Johnsen dans les commentaires. Merci!
pour des raisons d'exhaustivité, de nombreuses solutions utilisant sed
ou awk
ne traduisent qu'un ensemble spécial de caractères et sont donc assez grandes par taille de code et ne traduisent pas non plus d'autres caractères spéciaux qui devraient être encodés.
une façon sûre d'encoder urlencode serait de simplement encoder chaque octet - même ceux qui auraient été autorisés.
echo -ne 'some random\nbytes' | xxd -plain | tr -d '\n' | sed 's/\(..\)/%/g'
xxd prend soin ici que l'entrée soit traitée comme des octets et non caractère.
edit:
xxd est fourni avec le paquet vim-common dans Debian et j'étais sur un système où il n'était pas installé et je ne voulais pas l'installer. L'alternative est d'utiliser hexdump
du paquet bsdmainutils dans Debian. Selon le graphique suivant, bsdmainutils et vim-common devraient avoir une probabilité à peu près égale d'être installés:
mais néanmoins ici une version qui utilise hexdump
au lieu de xxd
et permet d'éviter l'appel tr
:
echo -ne 'some random\nbytes' | hexdump -v -e '/1 "%02x"' | sed 's/\(..\)/%/g'
je le trouve plus lisible en python:
encoded_value=$(python -c "import urllib; print urllib.quote('''$value''')")
le triple ' garantit que les devis simples en valeur ne fera pas de mal. urllib est dans la bibliothèque standard. Cela fonctionne pour exampple pour ce fou (monde réel) url:
"http://www.rai.it/dl/audio/" "1264165523944Ho servito il re d'Inghilterra - Puntata 7
une des variantes, peut être laid, mais simple:
urlencode() {
local data
if [[ $# != 1 ]]; then
echo "Usage: "151900920" string-to-urlencode"
return 1
fi
data="$(curl -s -o /dev/null -w %{url_effective} --get --data-urlencode "" "")"
if [[ $? != 3 ]]; then
echo "Unexpected error" 1>&2
return 2
fi
echo "${data##/?}"
return 0
}
Voici la version à une doublure par exemple (comme suggéré par Bruno ):
date | curl -Gso /dev/null -w %{url_effective} --data-urlencode @- "" | cut -c 3-
si vous souhaitez lancer la requête GET
et utiliser du curl pur, il suffit d'ajouter --get
à la solution de @Jacob's.
voici un exemple:
curl -v --get --data-urlencode "access_token=$(cat .fb_access_token)" https://graph.facebook.com/me/feed
Une autre option est d'utiliser jq
:
jq -s -R -r @uri
-s
( --slurp
) lit les lignes d'entrée dans un tableau et -s -R
( --slurp --raw-input
) lit l'entrée dans une seule chaîne. -r
( --raw-output
) affiche le contenu des chaînes au lieu des chaînes JSON.
ou ce pourcentage-code tous les octets:
xxd -p|tr -d \n|sed 's/../%&/g'
lien Direct vers la version awk: http://www.shelldorado.com/scripts/cmds/urlencode
Je l'ai utilisé pendant des années et il fonctionne comme un charme
:
##########################################################################
# 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 ""151900920""` # 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 "" 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 ("151900920"); ++i ) {
c = substr ("151900920", 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 ""
}
' "$@"
C'est peut-être le meilleur:
after=$(echo -e "$before" | od -An -tx1 | tr ' ' % | xargs printf "%s")
url=$(echo "" | 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')
cela encodera la chaîne à l'intérieur de $1 et la produira dans $url. bien que vous n'ayez pas à le mettre dans un var si vous voulez. BTW n'a pas inclus le sed pour l'onglet pensé qu'il allait le transformer en espaces
pour ceux d'entre vous qui cherchent une solution qui n'a pas besoin de perl, en voici une qui n'a besoin que de hexdump et awk:
url_encode() {
[ $# -lt 1 ] && { return; }
encodedurl="";
# 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 '
== "20" { printf("%s", "+"); next } # space becomes plus
~ /0[adAD]/ { next } # strip newlines
~ /^[a-zA-Z0-9.*()\/-]$/ { printf("%s", ); next } # pass through what we can
{ printf("%%%s", ) } # take hex value of everything else
'`
}
cousu ensemble à partir de quelques endroits à travers le net et certains essais et erreurs locales. Il fonctionne très bien!
utilisant php à partir d'un script shell:
value="http://www.google.com"
encoded=$(php -r "echo rawurlencode('$value');")
# encoded = "http%3A%2F%2Fwww.google.com"
echo $(php -r "echo rawurldecode('$encoded');")
# returns: "http://www.google.com"
Si vous ne voulez pas dépendre de Perl, vous pouvez également utiliser sed. C'est un peu désordonné, car chaque personnage doit être échappé individuellement. Créer un fichier avec le contenu suivant et l'appeler 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
pour l'utiliser, faites ce qui suit.
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"
cela divisera la chaîne en une partie qui a besoin d'encodage, et la partie qui est fine, encodera la partie qui en a besoin, puis recousera ensemble.
You peut mettre cela dans un script sh pour la commodité, peut-être le faire prendre un paramètre à encoder, le mettre sur votre chemin et puis vous pouvez juste appeler:
urlencode https://www.exxample.com?isThisFun=HellNo
la question Est de faire cela en bash et il n'y a pas besoin de python ou perl car il y a en fait une seule commande qui fait exactement ce que vous voulez - "urlencode".
value=$(urlencode "")
c'est aussi beaucoup mieux, car la réponse perl ci-dessus, par exemple, ne Code pas tous les caractères correctement. Essayez avec le long dash que vous obtenez de Word et vous obtenez le mauvais encodage.
Note, Vous avez besoin de "gridsite-clients" installé pour fournir cette commande.
vous pouvez imiter javascript encodeURIComponent
en perl. Voici la commande:
perl -pe 's/([^a-zA-Z0-9_.!~*()'\''-])/sprintf("%%%02X", ord())/ge'
vous pouvez définir ceci comme un alias bash dans .bash_profile
:
alias encodeURIComponent='perl -pe '\''s/([^a-zA-Z0-9_.!~*()'\''\'\'''\''-])/sprintf("%%%02X",ord())/ge'\'
Maintenant vous pouvez pipe dans encodeURIComponent
:
$ echo -n 'hèllo wôrld!' | encodeURIComponent
h%C3%A8llo%20w%C3%B4rld!
Simple option PHP:
echo 'part-that-needs-encoding' | php -R 'echo urlencode($argn);'
un Autre php approche:
echo "encode me" | php -r "echo urlencode(file_get_contents('php://stdin'));"
Voici la version du noeud:
uriencode() {
node -p "encodeURIComponent('${1//\'/\\'}')"
}
Ruby, par souci d'exhaustivité
value="$(ruby -r cgi -e 'puts CGI.escape(ARGV[0])' "")"
Voici une solution Bash qui n'invoque aucun programme externe:
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"
}
Voici une fonction POSIX pour faire cela:
encodeURIComponent() {
awk 'BEGIN {while (y++ < 125) z[sprintf("%c", y)] = y
while (y = substr(ARGV[1], ++j, 1))
q = y ~ /[[:alnum:]_.!~*()-]/ ? q y : q sprintf("%%%02X", z[y])
print q}' ""
}
exemple:
value=$(encodeURIComponent "")
voici une conversion d'une ligne en utilisant Lua, similaire à réponse de blueyed sauf avec tous les RFC 3986 caractères non réservés gauche non codé (comme cette réponse ):
url=$(echo 'print((arg[1]:gsub("([^%w%-%.%_%~])",function(c)return("%%%02X"):format(c:byte())end)))' | lua - "")
de plus, vous devrez peut-être vous assurer que les nouvelles lignes de votre chaîne sont converties de LF en CRLF, auquel cas vous pouvez insérer un gsub("\r?\n", "\r\n")
dans la chaîne avant le pourcentage d'encodage.
Voici une variante qui , dans le style non standard de l'application/x-www-form-urlencoded , fait que la normalisation newline, ainsi que l'encodage des espaces comme '+' au lieu de '%20' (qui pourrait probablement être ajouté à L'extrait Perl en utilisant une technique similaire).
url=$(echo 'print((arg[1]:gsub("\r?\n", "\r\n"):gsub("([^%w%-%.%_%~ ]))",function(c)return("%%%02X"):format(c:byte())end):gsub(" ","+"))' | lua - "")
ayant installé php j'utilise cette façon:
URL_ENCODED_DATA=`php -r "echo urlencode('$DATA');"`
C'est le ksh version de orwellophile de la réponse contenant la rawurlencode et rawurldecode fonctions (lien: Comment urlencode de données pour la commande curl? ). Je n'ai pas assez de rep pour poster un commentaire, d'où le nouveau post..
#!/bin/ksh93
function rawurlencode
{
typeset string=""
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++
voici ma version pour BusyBox Ash shell pour un système embarqué, j'ai à l'origine adopté la variante D'Orwellophile:
urlencode()
{
local S=""
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}"
}
ce qui suit est basé sur la réponse D'Orwellophile, mais résout le multibyte bug mentionné dans les commentaires en définissant LC_ALL=C (une astuce de vte.sh). Je l'ai écrit sous la forme de la fonction INVIT_COMMAND convenable, parce que c'est la façon dont je l'utilise.
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 "3]7;file://%s%s"151900920"7" "${HOSTNAME:-}" "${encoded}"
}
Qu'est-ce qui analyserait les URLs mieux que javascript?
node -p "encodeURIComponent('$url')"