507 votes

URLEncode d'un script bash

J'essaye d'écrire un script de bash pour le test qui prend un paramètre et l'envoie à travers curl au site Web. J'ai besoin d'url encoder la valeur pour s'assurer que les caractères spéciaux sont traités correctement. Quelle est la meilleure façon de procéder?

Voici mon script de base jusqu'à présent:

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

618voto

Jacob R Points 3370

Ou utilisez simplement curl --data-urlencode

228voto

Orwellophile Points 2695

Ici, c'est le pur BASH réponse.

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

  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 correspondance des rawurldecode() de la fonction, qui - en 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 le jeu 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, il va aller beaucoup plus vite, et susceptible de faire des fichiers binaires et plus...), j'ai trouvé cela sur mon routeur OpenWRT...

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

Où url_escape.sed est 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

102voto

dubek Points 2815

Utilisez les fonctions URI::Escape Perl et uri_escape de la deuxième ligne de votre script bash:

 ...

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

Edit: Correction de problèmes de citation, comme suggéré par Chris Johnsen dans les commentaires. Merci!

75voto

josch Points 790

par souci d'exhaustivité, de nombreuses solutions à l'aide d' sed ou awk seulement de traduire un ensemble de caractères et sont donc assez grand par la taille du code et aussi ne pas traduire d'autres caractères spéciaux qui doit être codé.

un moyen sûr de urlencode serait de simplement coder chaque octet - même ceux qui ont été autorisés.

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

xxd est ici que l'entrée est traitée comme octets et pas de caractères.

edit:

xxd est livré avec le vim-common paquets dans Debian et j'étais juste sur un système où il n'était pas installé et je ne voulais pas l'installer. Le altornative est d'utiliser hexdump de la bsdmainutils paquet dans Debian. Selon le graphique ci-dessous, bsdmainutils et vim-common devrait avoir une chance égale d'être installé:

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

mais néanmoins ici une version qui utilise hexdump au lieu de xxd et permet d'éviter l' tr appel:

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

63voto

sandro Points 139

Je le trouve plus lisible en python:

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

le triple garantit que les guillemets simples en valeur ne feront pas de mal. urllib est dans la bibliothèque standard. Cela fonctionne pour l'exemple de cette URL folle (du monde réel):

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X