97 votes

Comment décoder une chaîne codée en URL dans le shell ?

J'ai un fichier contenant une liste d'agents utilisateurs qui sont codés. Par exemple :

Mozilla%2F5.0%20%28Macintosh%3B%20U%3B%20Intel%20Mac%20OS%20X%2010.6%3B%20en

Je veux un shell script qui puisse lire ce fichier et écrire dans un nouveau fichier avec des chaînes décodées.

Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; en

J'ai essayé d'utiliser cet exemple pour le faire fonctionner, mais cela ne fonctionne pas pour l'instant.

$ echo -e "$(echo "%31+%32%0A%33+%34" | sed 'y/+/ /; s/%/\\x/g')"

Mon script ressemble à ça :

#!/bin/bash
for f in *.log; do
  echo -e "$(cat $f | sed 'y/+/ /; s/%/\x/g')" > y.log
done

141voto

guest Points 907

Voici une solution simple en une ligne.

$ function urldecode() { : "${*//+/ }"; echo -e "${_//%/\\x}"; }

Il peut ressembler à perl :) mais c'est juste du pur bash. Pas d'awks, pas de seds ... pas de frais généraux. Il utilise le buildin :, des paramètres spéciaux, la substitution de motifs et l'option -e du buildin echo pour traduire les codes hexadécimaux en caractères. Voir la page de manuel de bash pour plus de détails. Vous pouvez utiliser cette fonction comme une commande séparée

$ urldecode https%3A%2F%2Fgoogle.com%2Fsearch%3Fq%3Durldecode%2Bbash
https://google.com/search?q=urldecode+bash

ou dans les assignations de variables, comme ceci :

$ x="http%3A%2F%2Fstackoverflow.com%2Fsearch%3Fq%3Durldecode%2Bbash"
$ y=$(urldecode "$x")
$ echo "$y"
http://stackoverflow.com/search?q=urldecode+bash

46voto

Jay Points 301

Si vous êtes un python développeur, c'est peut-être préférable :

Pour Python 3.x (par défaut) :

echo -n "%21%20" | python3 -c "import sys; from urllib.parse import unquote; print(unquote(sys.stdin.read()));"

Pour Python 2.x (déprécié) :

echo -n "%21%20" | python -c "import sys, urllib as ul; print ul.unquote(sys.stdin.read());"

urllib est vraiment bon pour gérer l'analyse des URL

23voto

brendan Points 197

Avec BASH, pour lire l'URL encodée en pourcentage de la norme dans et décoder :

while read; do echo -e ${REPLY//%/\\x}; done

Pulse CTRL - D pour signaler la fin d'un fichier (EOF) et quitter gracieusement.

Vous pouvez décoder le contenu d'un fichier en définissant le fichier comme une entrée standard :

while read; do echo -e ${REPLY//%/\\x}; done < file

Vous pouvez décoder l'entrée d'un tuyau soit, par exemple :

echo 'a%21b' | while read; do echo -e ${REPLY//%/\\x}; done
  • La commande de lecture intégrée lit les données standard jusqu'à ce qu'elle voie un caractère de saut de ligne. Elle définit une variable appelée REPLY égale à la ligne de texte qu'il vient de lire.
  • ${REPLY//%/\\x} remplace toutes les occurrences de "%" par "". \x '.
  • echo -e interprète \xNN comme le caractère ASCII avec la valeur hexadécimale de NN .
  • while répète cette boucle jusqu'à ce que la commande de lecture échoue, par exemple si EOF a été atteint.

Ce qui précède ne change pas la valeur de '+' en ' '. Pour changer '+' en ' ' également, comme le fait l'invité réponse :

while read; do : "${REPLY//%/\\x}"; echo -e ${_//+/ }; done
  • : est une commande intégrée à BASH. Ici, elle prend juste un seul argument et ne fait rien avec.
  • Les guillemets doubles font de tout ce qui se trouve à l'intérieur un seul paramètre.
  • _ est un paramètre spécial qui est égal au dernier argument de la commande précédente, après expansion des arguments. C'est la valeur de REPLY avec toutes les occurrences de '%' remplacées par ''. \x '.
  • ${_//+/ } remplace toutes les occurrences de '+' par ' '.

Cela n'utilise que BASH et ne démarre aucun autre processus, comme dans la réponse de guest.

18voto

user785717 Points 757

C'est ce qui semble fonctionner pour moi.

#!/bin/bash
urldecode(){
  echo -e "$(sed 's/+/ /g;s/%\(..\)/\\x\1/g;')"
}

for f in /opt/logs/*.log; do
    name=${f##/*/}
    cat $f | urldecode > /opt/logs/processed/$HOSTNAME.$name
done

Remplacer les "+" par des espaces et les signes "%" par des "-". \x ', et en laissant echo interpréter les \x en utilisant l'option '-e' ne fonctionnait pas. Pour une raison quelconque, la commande cat imprimait le signe % sous sa propre forme codée %25. Ainsi, sed remplaçait simplement %25 par \x25. Lorsque l'option -e était utilisée, elle évaluait simplement \x25 comme % et la sortie était la même que l'original.

Trace :

Original : Mozilla%2F5.0%20%28Macintosh%3B%20U%3B%20Intel%20Mac%20OS%20X%2010.6%3B%20en

sed : Mozilla \x252F5.0\x2520\x2528Macintosh\x253B\x2520U\x253B\x2520Intel\x2520Mac\x2520OS\x2520X\x252010.6\x253B\x2520en

echo -e : Mozilla%2F5.0%20%28Macintosh%3B%20U%3B%20Intel%20Mac%20OS%20X%2010.6%3B%20en

Fixe : En gros, ignorez les 2 caractères après le % dans sed.

sed : Mozilla \x2F5.0\x20\x28Macintosh\x3B\x20U\x3B\x20Intel\x20Mac\x20OS\x20X\x2010.6\x3B\x20en

echo -e : Mozilla/5.0 (Macintosh ; U ; Intel Mac OS X 10.6 ; en

Je ne suis pas sûr des complications que cela pourrait entraîner, après des tests approfondis, mais cela fonctionne pour l'instant.

7voto

Janus Troelsen Points 5121

Bash script pour le faire en Bash natif ( source originale ) :

LANG=C

urlencode() {
    local l=${#1}
    for (( i = 0 ; i < l ; i++ )); do
        local c=${1:i:1}
        case "$c" in
            [a-zA-Z0-9.~_-]) printf "$c" ;;
            ' ') printf + ;;
            *) printf '%%%.2X' "'$c"
        esac
    done
}

urldecode() {
    local data=${1//+/ }
    printf '%b' "${data//%/\x}"
}

Si vous voulez urldécoder le contenu du fichier, il suffit de mettre le contenu du fichier comme argument.

Voici un test qui s'arrêtera si le contenu du fichier encodé décodé diffère (s'il s'exécute pendant quelques secondes, le script fonctionne probablement correctement) :

while true
  do cat /dev/urandom | tr -d '\0' | head -c1000 > /tmp/tmp;
     A="$(cat /tmp/tmp; printf x)"
     A=${A%x}
     A=$(urlencode "$A")
     urldecode "$A" > /tmp/tmp2
     cmp /tmp/tmp /tmp/tmp2
     if [ $? != 0 ]
       then break
     fi
done

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