Bash 如何在shell中解码URL编码的字符串?
我有一个文件,其中包含编码的用户代理列表。 例如:Bash 如何在shell中解码URL编码的字符串?,bash,shell,awk,sed,urldecode,Bash,Shell,Awk,Sed,Urldecode,我有一个文件,其中包含编码的用户代理列表。 例如: $ function urldecode() { : "${*//+/ }"; echo -e "${_//%/\\x}"; } 我想要一个shell脚本,它可以读取此文件并使用解码字符串写入新文件 Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; en $ function urldecode() { : "${*//+/ }"; echo -e "${_//%/\\x}"; } 我一直在尝
$ function urldecode() { : "${*//+/ }"; echo -e "${_//%/\\x}"; }
我想要一个shell脚本,它可以读取此文件并使用解码字符串写入新文件
Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; en
$ function urldecode() { : "${*//+/ }"; echo -e "${_//%/\\x}"; }
我一直在尝试使用这个例子来让它运行起来,但到目前为止它还不起作用
$ echo -e "$(echo "%31+%32%0A%33+%34" | sed 'y/+/ /; s/%/\\x/g')"
$ function urldecode() { : "${*//+/ }"; echo -e "${_//%/\\x}"; }
我的脚本看起来像:
#!/bin/bash
for f in *.log; do
echo -e "$(cat $f | sed 'y/+/ /; s/%/\x/g')" > y.log
done
$ function urldecode() { : "${*//+/ }"; echo -e "${_//%/\\x}"; }
正如评论中所说,\x
“应该是[double-]转义的”
$ function urldecode() { : "${*//+/ }"; echo -e "${_//%/\\x}"; }
我不会将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')
$ function urldecode() { : "${*//+/ }"; echo -e "${_//%/\\x}"; }
这似乎对我起了作用
#!/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
$ function urldecode() { : "${*//+/ }"; echo -e "${_//%/\\x}"; }
将“+”替换为空格,将%符号替换为“\x”转义符,并让echo使用“-e”选项解释\x转义符不起作用。由于某些原因,cat命令正在将%符号打印为其自己的编码形式%25。所以sed只是用\x25替换了%25。当使用-e选项时,它只是将\x25计算为%,输出与原始值相同
$ function urldecode() { : "${*//+/ }"; echo -e "${_//%/\\x}"; }
跟踪:
$ function urldecode() { : "${*//+/ }"; echo -e "${_//%/\\x}"; }
原创:Mozilla%2F5.0%20%28Macintosh%3B%20U%3B%20Intel%20Mac%20OS%20X%2010.6%3B%20en
$ function urldecode() { : "${*//+/ }"; echo -e "${_//%/\\x}"; }
sed:Mozilla\x252F5.0\x2520\x2528Macintosh\x253B\x2520U\x253B\x2520Intel\x2520Mac\x2520OS\x2520X\x252010.6\x253B\x2520en
$ function urldecode() { : "${*//+/ }"; echo -e "${_//%/\\x}"; }
echo-e:Mozilla%2F5.0%20%28Macintosh%3B%20U%3B%20Intel%20Mac%20OS%20X%2010.6%3B%20en
$ function urldecode() { : "${*//+/ }"; echo -e "${_//%/\\x}"; }
修复:基本上忽略sed中%后面的2个字符
$ function urldecode() { : "${*//+/ }"; echo -e "${_//%/\\x}"; }
sed:Mozilla\x2F5.0\x20\x28Macintosh\x3B\x20U\x3B\x20Intel\x20Mac\x20OS\x20X\x2010.6\x3B\x20en
$ function urldecode() { : "${*//+/ }"; echo -e "${_//%/\\x}"; }
echo-e:Mozilla/5.0(Macintosh;U;Intel Mac OS X 10.6;en
$ function urldecode() { : "${*//+/ }"; echo -e "${_//%/\\x}"; }
在经过大量测试后,我不确定这会导致什么复杂情况,但目前仍然有效。面对类似的问题,我最初的想法是在读取stdin或类似内容的脚本中使用PHP的urldecode,但后来我发现了这个想法。所有的答案似乎都有很多文本,但没有真正的解决方案。尽管这个想法很好,而且工作起来非常容易:
$ mpc | sed -e '1! d'
http://e.org/play.php?name=/Black%20Sun%20Empire%20-%20Sideways%20%28Feat.%20Illy%20Emcee%29
$ basename "$(echo -e `mpc | sed -e '1! d' -e 's/%/\\\\x/g'`)"
Black Sun Empire - Sideways (Feat. Illy Emcee)
$ function urldecode() { : "${*//+/ }"; echo -e "${_//%/\\x}"; }
使其工作的关键是双转义\x(这已经提到过)。在本机Bash()中执行此操作的Bash脚本:
$ function urldecode() { : "${*//+/ }"; echo -e "${_//%/\\x}"; }
如果您的服务器上安装了php,您可以很容易地使用url编码字符串“cat”甚至“tail”任何文件
tail -f nginx.access.log | php -R 'echo urldecode($argn)."\n";'
$ function urldecode() { : "${*//+/ }"; echo -e "${_//%/\\x}"; }
如果您是一名python开发人员,这可能更可取:
$ function urldecode() { : "${*//+/ }"; echo -e "${_//%/\\x}"; }
对于Python3.x(默认值):
$ function urldecode() { : "${*//+/ }"; echo -e "${_//%/\\x}"; }
对于Python2.x(已弃用):
$ function urldecode() { : "${*//+/ }"; echo -e "${_//%/\\x}"; }
非常擅长处理URL解析这里有一个在纯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
$ function urldecode() { : "${*//+/ }"; echo -e "${_//%/\\x}"; }
perl-pi.back-e'y/+/;s/%([\da-f]{2})/packh2,$1/gie./*.log
使用-i
将文件更新到位(一些sed
实现借用了perl
),并使用.back
作为备份扩展名
$ function urldecode() { : "${*//+/ }"; echo -e "${_//%/\\x}"; }
s/x/y/e
用y
perl代码的求值替换x
$ function urldecode() { : "${*//+/ }"; echo -e "${_//%/\\x}"; }
本例中的perl代码使用pack
将$1
中捕获的十六进制数(regexp中的第一个括号对)打包为相应的字符
$ function urldecode() { : "${*//+/ }"; echo -e "${_//%/\\x}"; }
pack
的替代方法是使用chr(十六进制($1))
:
$ function urldecode() { : "${*//+/ }"; echo -e "${_//%/\\x}"; }
perl-pi.back-e'y/+/;s/%([\da-f]{2})/chr hex$1/gie./*.log
如果可用,还可以使用uri\u unescape()
中的uri::Escape
:
$ function urldecode() { : "${*//+/ }"; echo -e "${_//%/\\x}"; }
perl-pi.back-MURI::Escape-e'y/+/$\u=uri\u unescape$\u./*.log
带GNUawk
:
$ function urldecode() { : "${*//+/ }"; echo -e "${_//%/\\x}"; }
LC_ALL=C gawk-vRS='%[:xdigit:]{2}'
RT{RT=sprintf(“%c”,strtonum(“0x”substr(RT,2)))}
{gsub(/\+/,“”);printf“%s”,“$0 RT}”
将采用标准输入法上编码的URI,并在标准输出法上打印解码后的输出
$ function urldecode() { : "${*//+/ }"; echo -e "${_//%/\\x}"; }
我们将记录分隔符设置为与
%XX
序列匹配的regexp。在GNUawk
中,匹配它的输入存储在RT特殊变量中。我们从那里提取十六进制数字,将strnum()
附加到“0x”后变成一个数字,依次传递到sprintf(“%c”)
在C语言环境中会转换为相应的字节值。只是想分享另一个解决方案,pure 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
$ function urldecode() { : "${*//+/ }"; echo -e "${_//%/\\x}"; }
Python answer的一个稍加修改的版本,它接受一行程序中的输入和输出文件
cat inputfile.txt | python -c "import sys, urllib as ul; print ul.unquote(sys.stdin.read());" > ouputfile.txt
$ function urldecode() { : "${*//+/ }"; echo -e "${_//%/\\x}"; }
这里是一个简单的单线解决方案
$ function urldecode() { : "${*//+/ }"; echo -e "${_//%/\\x}"; }
它可能看起来像perl:),但它只是纯bash。没有AWK,没有SED。。。没有间接费用。使用:内置、特殊参数、模式替换和echo内置的-e选项将十六进制代码转换为字符。有关更多详细信息,请参阅bash的手册页。您可以将此函数用作单独的命令
$ function urldecode() { : "${*//+/ }"; echo -e "${_//%/\\x}"; }
$ urldecode https%3A%2F%2Fgoogle.com%2Fsearch%3Fq%3Durldecode%2Bbash
https://google.com/search?q=urldecode+bash
或者在变量赋值中,例如:
$ function urldecode() { : "${*//+/ }"; echo -e "${_//%/\\x}"; }
$ x="http%3A%2F%2Fstackoverflow.com%2Fsearch%3Fq%3Durldecode%2Bbash"
$ y=$(urldecode "$x")
$ echo "$y"
http://stackoverflow.com/search?q=urldecode+bash
使用BASH,要从标准输入读取%编码的URL并解码:
$ function urldecode() { : "${*//+/ }"; echo -e "${_//%/\\x}"; }
while read; do echo -e ${REPLY//%/\\x}; done
按CTRL-D以发出文件结束(EOF)的信号,然后优雅地退出
$ function urldecode() { : "${*//+/ }"; echo -e "${_//%/\\x}"; }
通过将文件设置为标准文件,可以解码文件的内容:
$ function urldecode() { : "${*//+/ }"; echo -e "${_//%/\\x}"; }
while read; do echo -e ${REPLY//%/\\x}; done < file
- read-build-in命令读取标准输入,直到看到换行符为止。它将一个名为
的变量设置为它刚刚读取的文本行REPLY
将“%”的所有实例替换为“\x”${REPLY//%/\\x}
将echo-e
解释为十六进制值为\xNN
的ASCII字符NN
- while重复此循环,直到read命令失败,例如达到EOF
$ function urldecode() { : "${*//+/ }"; echo -e "${_//%/\\x}"; }
是一个BASH内置命令。在这里,它只接受一个参数,不做任何处理:
- 双引号将所有内容放在一个参数内
是一个特殊参数,它等于参数展开后上一个命令的最后一个参数。这是\
的值,其中“%”的所有实例都替换为“\x”REPLY
将“+”的所有实例替换为${{u//+/}