web-dev-qa-db-fra.com

Comment décoder une chaîne encodée en URL dans un shell?

J'ai un fichier avec une liste de user-agents qui sont encodés . E.g .:

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

Je veux un script shell capable de lire ce fichier et d’é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 mettre en marche, mais cela ne fonctionne pas jusqu'à présent.

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

Mon script ressemble à:

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

Voici une solution simple en une ligne. 

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

Cela peut ressembler à Perl :) mais ce n'est que purement bash. Pas de awks, pas de seds ... pas de frais généraux. Utilisation de: builtin, de paramètres spéciaux, de substitution de modèle et de l'option -e intégrée de 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 en tant que commande séparée

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

ou dans des affectations 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
31
guest

GNU awk

#!/usr/bin/awk -fn
@include "ord"
BEGIN {
  RS = "%.."
}
{
  printf RT ? $0 chr("0x" substr(RT, 2)) : $0
}

Ou

#!/bin/sh
awk -niord '{printf RT?$0chr("0x"substr(RT,2)):$0}' RS=%..

Utilisation de awk printf pour urldecode text

18
Steven Penny

С BASH, чтобы прочитать, процентный, кодированный, URL pour afficher l'URL de la page:

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

НажмитеCTRL-Dсигнализировать об окончании файла (EOF) и корректно завершить работу.

Вы можете декодировать содержимое файла, установив его стандартным в:

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

Вы можете декодировать входные данные из канала, например:

echo 'a%21b' | while read; do echo -e ${REPLY//%/\\x}; done
  • Встроенная команда lire читает стандарт de votre mot de passe, cliquez sur le lien suivant. Он устанавливает переменную с именем REPLY равной строке текста, которую он только чточка.
  • ${REPLY//%/\\x} заменяет все экземпляры "%" на "\ x".
  • echo -e интерпретирует \xNN как символ ASCII с шестнадцатеричным значением NN.
  • bien que tout soit en ordre, en nombre, en nombre, en nombre, en nombre, en nombre, en hauteur et en valeur. EOF достигнуто.

Вышеуказанное не меняет "+" на "". Тобы изменить '+' на '' также, как в гостевой ответ :

while read; do : "${REPLY//%/\\x}"; echo -e ${_//+/ }; done
  • : - встроенная команда BASH. Здесь он просто принимает один аргумент и ничего не делает с ним.
  • Двойные кавычки делают все внутри одного параметра.
  • _ - то специальный параметр, который равен последнему аргументу предыдущей команды Nom de domaine REPLY со всеми кземплярами "%", замененными на "\ x".
  • ${_//+/ } заменяет все экземпляры '+' на ''.

При этом используется только BASH et plus encore, qui est Аналогичный.

11
brendan

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 '\ x' échappés et laisser l'écho interpréter les échappements\x à l'aide de 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 avec\x25. Lorsque l'option -e était utilisée, elle évaluait simplement\x25 en tant que% et le résultat était identique à 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

Correction: Ignorer fondamentalement 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\x20

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

Je ne sais pas quelles complications cela entraînerait, après de nombreux tests, mais cela fonctionne pour le moment.

9
user785717

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

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

urllib fait preuve de professionnalisme

8
Jay

Script Bash 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 utiliser urldecode pour le contenu du fichier, il suffit de le définir comme argument.

Voici un test qui s'exécutera si le contenu du fichier codé décodé diffère (s'il fonctionne 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
6
Janus Troelsen
Perl -pi.back -e 'y/+/ /;s/%([\da-f]{2})/pack H2,$1/gie' ./*.log

Avec -i met à jour les fichiers sur place (certaines implémentations de sed l'ont empruntée à Perl) avec .back comme extension de sauvegarde.

s/x/y/e remplace x par le evalorisation du code y Perl.

Le code Perl dans ce cas utilise pack pour compresser le nombre hexadécimal capturé dans $1 (première paire de parenthèses dans l’expression rationnelle) en tant que caractère correspondant.

Une alternative à pack consiste à utiliser chr(hex($1)):

Perl -pi.back -e 'y/+/ /;s/%([\da-f]{2})/chr hex $1/gie' ./*.log

Si disponible, vous pouvez également utiliser uri_unescape() à partir de URI::Escape:

Perl -pi.back -MURI::Escape -e 'y/+/ /;$_=uri_unescape$_' ./*.log
6

Si vous avez php installé sur votre serveur, vous pouvez "cat" ou même "tail" n'importe quel fichier, avec des chaînes encodées très facilement.

tail -f nginx.access.log | php -R 'echo urldecode($argn)."\n";'
4
Oleg Bondar'

Comme @barti_ddu a déclaré dans les commentaires, \x "devrait être [double-] échappé".

% echo -e "$(echo "Mozilla%2F5.0%20%28Macintosh%3B%20U%3B%20Intel%20Mac%20OS%20X%2010.6%3B%20en" | sed 'y/+/ /; s/%/\\x/g')"
Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; en

Plutôt que de mélanger Bash et sed, je referais tout cela en Python. Voici un aperçu de la façon dont:

#!/usr/bin/env python

import glob
import os
import urllib

for logfile in glob.glob(os.path.join('.', '*.log')):
    with open(logfile) as current:
        new_log_filename = logfile + '.new'
        with open(new_log_filename, 'w') as new_log_file:
            for url in current:
                unquoted = urllib.unquote(url.strip())
                new_log_file.write(unquoted + '\n')
4
Johnsyweb

Avec GNU awk:

gawk -vRS='%[0-9a-fA-F]{2}' 'RT{sub("%","0x",RT);RT=sprintf("%c",strtonum(RT))}
                             {gsub(/\+/," ");printf "%s", $0 RT}'
3

Voici une solution réalisée en bash pur où entrée et sortie sont des variables bash. Il décodera le '+' en tant qu'espace et gérera l'espace '% 20', ainsi que les autres caractères codés en%. 

#!/bin/bash
#here is text that contains both '+' for spaces and a %20
text="hello+space+1%202"
decoded=$(echo -e `echo $text | sed 's/+/ /g;s/%/\\\\x/g;'`)
echo decoded=$decoded
2
nevertooloud
$ uenc='H%C3%B6he %C3%BCber%20dem%20Meeresspiegel'
$ utf8=$(echo -e "${uenc//%/\\x}")
$ echo $utf8
Höhe über dem Meeresspiegel
$
2
guest

Extension à https://stackoverflow.com/a/37840948/8142470
pour travailler avec des entités HTML

$ htmldecode () {: "$ {* // + /}"; echo -e "$ {_ // & # x/\ x}" | tr -d ';'; }
$ htmldecode "http & # x3A; & # x2F; & # x2F; google.com & # x2F; rechercher && # x3F; q & # x3D; urldecode & # x2B; bash" http://google.com/search&?q=urldecode+bash

(l'argument doit être cité)

0
Calvin Kim