我试图写一个bash脚本测试,需要一个参数,并通过curl发送到网站。我需要url编码的值,以确保特殊字符被正确处理。最好的方法是什么?
这是我到目前为止的基本脚本:
#!/bin/bash
host=${1:?'bad host'}
value=$2
shift
shift
curl -v -d "param=${value}" http://${host}/somepath $@
我试图写一个bash脚本测试,需要一个参数,并通过curl发送到网站。我需要url编码的值,以确保特殊字符被正确处理。最好的方法是什么?
这是我到目前为止的基本脚本:
#!/bin/bash
host=${1:?'bad host'}
value=$2
shift
shift
curl -v -d "param=${value}" http://${host}/somepath $@
当前回答
下面是一个POSIX函数:
url_encode() {
awk 'BEGIN {
for (n = 0; n < 125; n++) {
m[sprintf("%c", n)] = n
}
n = 1
while (1) {
s = substr(ARGV[1], n, 1)
if (s == "") {
break
}
t = s ~ /[[:alnum:]_.!~*\47()-]/ ? t s : t sprintf("%%%02X", m[s])
n++
}
print t
}' "$1"
}
例子:
value=$(url_encode "$2")
其他回答
使用curl——data-urlencode;来自man curl:
它发布数据,类似于其他——data选项,不同的是它执行url编码。为了与cgi兼容,<data>部分应该以名称开头,后面跟着分隔符和内容规范。
使用示例:
curl \
--data-urlencode "paramName=value" \
--data-urlencode "secondParam=value" \
http://example.com
有关更多信息,请参阅手册页。
这需要curl 7.18.0或更新版本(发布于2008年1月)。使用curl -V来检查您拥有的版本。
你也可以对查询字符串进行编码:
curl --get \
--data-urlencode "p1=value 1" \
--data-urlencode "p2=value 2" \
http://example.com
# http://example.com?p1=value%201&p2=value%202
Ruby,为了完整性
value="$(ruby -r cgi -e 'puts CGI.escape(ARGV[0])' "$2")"
我发现下面的代码片段很有用,可以将它插入到一个程序调用链中,其中URI::Escape可能没有安装:
perl -p -e 's/([^A-Za-z0-9])/sprintf("%%%02X", ord($1))/seg'
(源)
下面是纯BASH的答案。
更新:由于已经讨论了许多变化,我已经把这个放在https://github.com/sfinktah/bash/blob/master/rawurlencode.inc.sh上,任何人都可以发布一个PR。
注意:这个解决方案并不打算编码unicode或多字节字符——这完全超出了BASH的简单本机功能。它仅用于编码那些在POST或GET请求中会破坏参数传递的符号,例如。'&', '='等等。
非常重要的提示:不要尝试用任何语言编写你自己的UNICODE转换函数。见答案结尾。
rawurlencode() {
local string="${1}"
local strlen=${#string}
local encoded=""
local pos c o
for (( pos=0 ; pos<strlen ; pos++ )); do
c=${string:$pos:1}
case "$c" in
[-_.~a-zA-Z0-9] ) o="${c}" ;;
* ) printf -v o '%%%02x' "'$c"
esac
encoded+="${o}"
done
echo "${encoded}" # You can either set a return variable (FASTER)
REPLY="${encoded}" #+or echo the result (EASIER)... or both... :p
}
你可以在两种情况下使用它:
easier: echo http://url/q?=$( rawurlencode "$args" )
faster: rawurlencode "$args"; echo http://url/q?${REPLY}
(编辑)
下面是匹配的rawurldecode()函数,它非常棒。
# Returns a string in which the sequences with percent (%) signs followed by
# two hex digits have been replaced with literal characters.
rawurldecode() {
# This is perhaps a risky gambit, but since all escape characters must be
# encoded, we can replace %NN with \xNN and pass the lot to printf -b, which
# will decode hex for us
printf -v REPLY '%b' "${1//%/\\x}" # You can either set a return variable (FASTER)
echo "${REPLY}" #+or echo the result (EASIER)... or both... :p
}
有了匹配集,我们现在可以执行一些简单的测试:
$ diff rawurlencode.inc.sh \
<( rawurldecode "$( rawurlencode "$( cat rawurlencode.inc.sh )" )" ) \
&& echo Matched
Output: Matched
如果你真的觉得你需要一个外部工具(好吧,它会快得多,可能会处理二进制文件之类的…)我在我的OpenWRT路由器上发现了这个…
replace_value=$(echo $replace_value | sed -f /usr/lib/ddns/url_escape.sed)
url_escape的地方。Sed是一个包含以下规则的文件:
# sed url escaping
s:%:%25:g
s: :%20:g
s:<:%3C:g
s:>:%3E:g
s:#:%23:g
s:{:%7B:g
s:}:%7D:g
s:|:%7C:g
s:\\:%5C:g
s:\^:%5E:g
s:~:%7E:g
s:\[:%5B:g
s:\]:%5D:g
s:`:%60:g
s:;:%3B:g
s:/:%2F:g
s:?:%3F:g
s^:^%3A^g
s:@:%40:g
s:=:%3D:g
s:&:%26:g
s:\$:%24:g
s:\!:%21:g
s:\*:%2A:g
虽然在BASH中编写这样一个能够处理UTF-8输入的脚本(可能使用xxd和一个非常长的规则集)并不是不可能的,但是有更快更可靠的方法。试图将UTF-8解码为UTF-32是一项非常重要的任务,要做到准确,尽管很容易做得不准确,以至于您认为它有效,直到有一天它不起作用。
甚至Unicode联盟在发现样本代码不再100%与实际标准兼容后,也删除了样本代码。
Unicode标准在不断发展,变得非常微妙。您可以拼凑的任何实现都不会具有适当的遵从性,如果您通过一些极端的努力来管理它,它也不会保持遵从性。
如果你想运行GET请求并使用纯curl,只需添加—得到@Jacob的解决方案。
这里有一个例子:
curl -v --get --data-urlencode "access_token=$(cat .fb_access_token)" https://graph.facebook.com/me/feed