エンコードされたユーザーエージェントのリストを含むファイルがあります。例えば。:
Mozilla%2F5.0%20%28Macintosh%3B%20U%3B%20Intel%20Mac%20OS%20X%2010.6%3B%20en
このファイルを読み取り、デコードされた文字列で新しいファイルに書き込むことができるシェルスクリプトが必要です。
Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; en
私はこの例を使ってそれを実現しようとしましたが、今のところうまくいきません。
$ echo -e "$(echo "%31+%32%0A%33+%34" | sed 'y/+/ /; s/%/\\x/g')"
私のスクリプトは次のようになります:
#!/bin/bash
for f in *.log; do
echo -e "$(cat $f | sed 'y/+/ /; s/%/\x/g')" > y.log
done
簡単な1行のソリューションを次に示します。
$ urldecode() { : "${*//+/ }"; echo -e "${_//%/\\x}"; }
Perlのように見えるかもしれません:)しかし、それは単なるbashです。 awks、seds、オーバーヘッドなし。 :ビルトイン、特殊パラメーター、パターン置換、およびエコービルトインの-eオプションを使用して、16進コードを文字に変換します。詳細については、bashのマンページを参照してください。この関数を個別のコマンドとして使用できます
$ urldecode https%3A%2F%2Fgoogle.com%2Fsearch%3Fq%3Durldecode%2Bbash
https://google.com/search?q=urldecode+bash
または、変数の割り当てなどで:
$ 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
}
または
#!/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)を通知し、正常に終了します。
ファイルを以下の標準に設定することにより、ファイルの内容をデコードできます。
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 16進値NN
の文字として解釈します。上記は「+」を「」に変更しません。ゲストの answer のように、「+」を「」にも変更するには:
while read; do : "${REPLY//%/\\x}"; echo -e ${_//+/ }; done
:
はBASH組み込みコマンドです。ここでは、単一の引数を取り、それに対して何もしません。_
は、引数の展開後、前のコマンドの最後の引数に等しい特別なパラメーターです。これはREPLY
の値で、 '%'のすべてのインスタンスが '\ x'に置き換えられます。${_//+/ }
は、 '+'のすべてのインスタンスを ''に置き換えます。これはBASHのみを使用し、ゲストの回答と同様に他のプロセスを開始しません。
これは私のために働いているようです。
#!/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
'+'をスペースに、%記号を '\ x'エスケープに置き換え、エコーに '-e'オプションを使用して\ xエスケープを解釈させていませんでした。何らかの理由で、catコマンドは%記号を独自のエンコード形式%25として出力していました。したがって、sedは単に%25を\ x25に置き換えていました。 -eオプションを使用した場合、単に\ x25を%として評価し、出力は元のものと同じでした。
トレース:
オリジナル: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
修正:基本的に、sedの%の後の2文字を無視します。
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
広範なテストの後、これがどのような複雑さをもたらすかはわかりませんが、今のところは機能します。
あなたがpython開発者である場合、これはおそらくより好ましい
echo "%21%20" | python -c "import sys, urllib as ul; print ul.unquote(sys.stdin.read());"
rllib はそれを処理するのにプロです。
_Perl -pi.back -e 'y/+/ /;s/%([\da-f]{2})/pack H2,$1/gie' ./*.log
_
_-i
_を使用すると、ファイルがインプレースで更新されます(一部のsed
実装は、Perl
からそれを借用します)。バックアップ拡張機能として_.back
_を使用します。
_s/x/y/e
_はx
を ey
Perlコードの評価。
この場合のPerlコードは、pack
を使用して、_$1
_(正規表現の最初の括弧のペア)でキャプチャされた16進数を対応する文字としてパックします。
pack
の代わりにchr(hex($1))
を使用することもできます:
_Perl -pi.back -e 'y/+/ /;s/%([\da-f]{2})/chr hex $1/gie' ./*.log
_
利用可能な場合、_URI::Escape
_のuri_unescape()
も使用できます。
_Perl -pi.back -MURI::Escape -e 'y/+/ /;$_=uri_unescape$_' ./*.log
_
ネイティブBashで実行するためのBashスクリプト( 元のソース ):
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}"
}
ファイルコンテンツをurldecodeする場合は、ファイルコンテンツを引数として入力します。
エンコードされたエンコード済みファイルの内容が異なる場合に停止するテストを次に示します(数秒間実行すると、スクリプトはおそらく正しく動作します)。
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
サーバーにphpがインストールされている場合は、URLエンコードされた文字列を使用して、任意のファイルを「cat」または「tail」できます。
tail -f nginx.access.log | php -R 'echo urldecode($argn)."\n";'
@ barti_dd がコメントで述べたように、\x
「[ダブル]エスケープする必要があります」。
% 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
Bashとsedを混同するのではなく、これをすべてPythonで行います。大まかな方法は次のとおりです。
#!/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')
GNU awk
の場合:
gawk -vRS='%[0-9a-fA-F]{2}' 'RT{sub("%","0x",RT);RT=sprintf("%c",strtonum(RT))}
{gsub(/\+/," ");printf "%s", $0 RT}'
これは、入力と出力がbash変数である純粋なbashで行われる解決策です。スペースとして「+」をデコードし、「%20」スペースと他の%エンコード文字を処理します。
#!/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
$
https://stackoverflow.com/a/37840948/814247 に展開
HTMLエンティティを操作する
$ htmldecode(){: "$ {* // + /}"; echo -e "$ {_ //#x/\ x}" | tr -d ';'; }
$ htmldecode "http#x3A;#x2F;#x2F; google.com#x2F; search#x3F; q#x3D; urldecode#x2B; bash" http://google.com/ search?q = urldecode + bash
(引数を引用する必要があります)