70

エンコードされたユーザーエージェントのリストを含むファイルがあります。例えば:

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
4

21 に答える 21

27

あなたがPython開発者である場合、これが望ましいかもしれません:

Python 3.x (デフォルト) の場合:

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

Python 2.x (非推奨) の場合:

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

urllibは、URL 解析の処理が非常に得意です

于 2014-02-11T04:55:56.023 に答える
15

これは私のために働いているようです。

#!/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」オプションを使用して echo に \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

広範なテストの後、これがどのような合併症を引き起こすかはわかりませんが、今のところ機能します。

于 2011-06-07T12:42:40.287 に答える
7
perl -pi.back -e 'y/+/ /;s/%([\da-f]{2})/pack H2,$1/gie' ./*.log

-iファイルをインプレースで更新すると (一部の実装sedでは から借用していますperl) .back、バックアップ拡張子として使用します。

s/x/y/eperl コードxe評価に置き換えます。y

この場合の perl コードは、キャプチャされた 16 進数(正規表現の最初の括弧のペア) を対応する文字としてpackパックするために使用します。$1

に代わるものpackは、次を使用することchr(hex($1))です。

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

uri_unescape()利用可能な場合は、 fromも使用できますURI::Escape

perl -pi.back -MURI::Escape -e 'y/+/ /;$_=uri_unescape$_' ./*.log
于 2014-05-01T12:03:24.227 に答える
6

ネイティブ 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}"
}

ファイル コンテンツを URL デコードする場合は、ファイル コンテンツを引数として指定します。

デコードされたエンコードされたファイルのコンテンツが異なる場合に停止を実行するテストを次に示します (数秒間実行すると、スクリプトはおそらく正しく動作します)。

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
于 2013-05-02T09:55:28.250 に答える
5

@barti_dduがコメントで述べたように、 「[ double-\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')
于 2011-06-06T11:39:59.960 に答える
5

サーバーに php がインストールされている場合は、url でエンコードされた文字列を使用して、任意のファイルを非常に簡単に "cat" または "tail" することができます。

tail -f nginx.access.log | php -R 'echo urldecode($argn)."\n";'
于 2013-11-06T04:49:09.313 に答える
2

GNU の場合awk:

LC_ALL=C gawk -vRS='%[[:xdigit:]]{2}' '
  RT {RT = sprintf("%c",strtonum("0x" substr(RT, 2)))}
  {gsub(/\+/," ");printf "%s", $0 RT}'

stdin で URI エンコードされたものを取得し、デコードされた出力を stdout に出力します。

%XXレコード セパレータを、シーケンスに一致する正規表現として設定します。GNUawkでは、それに一致した入力は RT 特殊変数に格納されます。そこから 16 進数を抽出し、"0x" に追加して数値に変換し、C ロケールで対応するバイト値に変換するためにstrnum()渡されます。sprintf("%c")

于 2014-05-01T13:58:00.827 に答える
0

これは、入力と出力が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
于 2014-03-07T15:21:28.263 に答える
-1

この他のソリューション、純粋なbashを共有したかっただけです:

encoded_string="Mozilla%2F5.0%20%28Macintosh%3B%20U%3B%20Intel%20Mac%20OS%20X%2010.6%3B%20en"
printf -v encoded_string "%b" "${encoded_string//\%/\x}"
echo $encoded_string
于 2014-06-02T20:56:10.267 に答える
-1

1 つのライナーで入力ファイルと出力ファイルを受け入れる、Python の回答のわずかに変更されたバージョン。

cat inputfile.txt | python -c "import sys, urllib as ul; print ul.unquote(sys.stdin.read());" > ouputfile.txt
于 2014-08-07T21:06:18.413 に答える