Ich habe eine Datei mit einer Liste von Benutzeragenten, die verschlüsselt sind . E.g .:
Mozilla%2F5.0%20%28Macintosh%3B%20U%3B%20Intel%20Mac%20OS%20X%2010.6%3B%20en
Ich möchte ein Shell-Skript, das diese Datei lesen und in eine neue Datei mit dekodierten Zeichenfolgen schreiben kann.
Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; en
Ich habe versucht, dieses Beispiel zu verwenden, um es in Gang zu bringen, aber es funktioniert bisher nicht.
$ echo -e "$(echo "%31+%32%0A%33+%34" | sed 'y/+/ /; s/%/\\x/g')"
Mein Skript sieht so aus:
#!/bin/bash
for f in *.log; do
echo -e "$(cat $f | sed 'y/+/ /; s/%/\x/g')" > y.log
done
Hier ist eine einfache einzeilige Lösung.
$ urldecode() { : "${*//+/ }"; echo -e "${_//%/\\x}"; }
Es mag wie Perl aussehen :), aber es ist nur pure Bash. Keine Felle, keine Seds ... keine Gemeinkosten. Verwenden Sie: builtin, spezielle Parameter, Mustersubstitution und die Option -e des Echo Builtins, um Hex-Codes in Zeichen zu übersetzen. Weitere Informationen finden Sie in der Manpage von bash. Sie können diese Funktion als separaten Befehl verwenden
$ urldecode https%3A%2F%2Fgoogle.com%2Fsearch%3Fq%3Durldecode%2Bbash
https://google.com/search?q=urldecode+bash
oder in variablen Zuweisungen, wie so:
$ 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
}
Oder
#!/bin/sh
awk -niord '{printf RT?$0chr("0x"substr(RT,2)):$0}' RS=%..
С BASH, чтобы прочитать процентный кодированный URL из стандартного ввода и декодировать:
while read; do echo -e ${REPLY//%/\\x}; done
НажмитеCTRL-Dсигнализировать об окончании файла (EOF) und корректно завершить работу.
Weitere Informationen zum Thema:
while read; do echo -e ${REPLY//%/\\x}; done < file
Weitere Informationen zum Thema:
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. Здесь он просто принимает один аргумент и ничего не делает с ним._
- это специальный параметр. Это значение REPLY
со всеми экземплярами "%", замененными на "\ x".${_//+/ }
заменяет все экземпляры '+' на ''.При этом используется только BASH и не запускается никакой другой процесс, аналогичный ответу гостя.
Das scheint für mich zu funktionieren.
#!/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
Das Ersetzen von '+' durch Leerzeichen und% -Zeichen durch '\ x'-Escapezeichen, und das Echo der\x-Escapezeichen mit der' -e'-Option interpretieren zu lassen, funktionierte nicht. Aus irgendeinem Grund druckte der Befehl cat das% -Zeichen als eigenes codiertes Formular% 25. Sed hat also einfach% 25 durch\x25 ersetzt. Wenn die Option -e verwendet wurde, wurde\x25 einfach als% ausgewertet, und die Ausgabe entsprach der des Originals.
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
Fix: Ignoriere grundsätzlich die 2 Zeichen nach dem% in 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; de
Ich bin nicht sicher, welche Komplikationen dies nach umfangreichen Tests zur Folge haben würde, aber es funktioniert im Moment.
wenn Sie ein python - Entwickler sind, ist dies möglicherweise vorzuziehen
echo "%21%20" | python -c "import sys, urllib as ul; print ul.unquote(sys.stdin.read());"
urllib ist professionell im Umgang damit
Bash-Skript für die Verwendung in nativen Bash ( Originalquelle ):
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}"
}
Wenn Sie den Inhalt der Datei urldecodeen möchten, geben Sie den Inhalt der Datei einfach als Argument an.
Hier ist ein Test, der angehalten wird, wenn sich der Inhalt der decodierten codierten Datei unterscheidet (wenn er einige Sekunden läuft, funktioniert das Skript wahrscheinlich richtig)
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
Mit -i
werden die Dateien vor Ort aktualisiert (einige sed
-Implementierungen haben diese aus Perl
ausgeliehen) mit .back
als Sicherungserweiterung.
s/x/y/e
ersetzt x
durch die ebewertung des y
Perl-Codes.
Der Perl-Code verwendet in diesem Fall pack
, um die in $1
erfasste Hex-Zahl (erstes Klammerpaar im regulären Ausdruck) als entsprechendes Zeichen zu packen.
Eine Alternative zu pack
ist die Verwendung von chr(hex($1))
:
Perl -pi.back -e 'y/+/ /;s/%([\da-f]{2})/chr hex $1/gie' ./*.log
Falls verfügbar, können Sie auch uri_unescape()
aus URI::Escape
verwenden:
Perl -pi.back -MURI::Escape -e 'y/+/ /;$_=uri_unescape$_' ./*.log
Wenn Sie php auf Ihrem Server installiert haben, können Sie jede Datei sehr einfach "cat" oder sogar "tail" machen.
tail -f nginx.access.log | php -R 'echo urldecode($argn)."\n";'
Wie @barti_ddu in den Kommentaren sagte, sollte \x
"[double-] escaped sein".
% 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
Anstatt Bash und Sed zu mischen, würde ich das alles in Python machen. Hier ist ein grober Schnitt wie:
#!/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')
Mit GNU awk
:
gawk -vRS='%[0-9a-fA-F]{2}' 'RT{sub("%","0x",RT);RT=sprintf("%c",strtonum(RT))}
{gsub(/\+/," ");printf "%s", $0 RT}'
Hier ist eine Lösung, die in reinen Bashs ausgeführt wird, wobei Eingabe und Ausgabe Bash-Variablen sind. Es dekodiert '+' als Leerzeichen und behandelt das '% 20'-Leerzeichen sowie andere% -kodierte Zeichen.
#!/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
$
Erweiterung zu https://stackoverflow.com/a/37840948/8142470
um mit HTML-Entitäten zu arbeiten
$ htmldecode () {: "$ {* // + /}"; echo -e "$ {_ // & # x/\ x}" | tr -d ';'; }
$ htmldecode "http & # x3A; & # x2F; & # x2F; google.com Suche && # x3F; q & # x3D; URL-Code & # x2B; bash" http://google.com/search&?q=urldecode+bash
(Argument muss zitiert werden)