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
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
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=%..
С 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
REPLY
равной строке текста, которую он только чточка.${REPLY//%/\\x}
заменяет все экземпляры "%" на "\ x".echo -e
интерпретирует \xNN
как символ ASCII с шестнадцатеричным значением NN
.Вышеуказанное не меняет "+" на "". Тобы изменить '+' на '' также, как в гостевой ответ :
while read; do : "${REPLY//%/\\x}"; echo -e ${_//+/ }; done
:
- встроенная команда BASH. Здесь он просто принимает один аргумент и ничего не делает с ним._
- то специальный параметр, который равен последнему аргументу предыдущей команды Nom de domaine REPLY
со всеми кземплярами "%", замененными на "\ x".${_//+/ }
заменяет все экземпляры '+' на ''.При этом используется только BASH et plus encore, qui est Аналогичный.
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.
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
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
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
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";'
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')
Avec GNU awk
:
gawk -vRS='%[0-9a-fA-F]{2}' 'RT{sub("%","0x",RT);RT=sprintf("%c",strtonum(RT))}
{gsub(/\+/," ");printf "%s", $0 RT}'
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
$ uenc='H%C3%B6he %C3%BCber%20dem%20Meeresspiegel'
$ utf8=$(echo -e "${uenc//%/\\x}")
$ echo $utf8
Höhe über dem Meeresspiegel
$
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é)