【问题标题】:Properly using curl --data-urlencode when passing a variable传递变量时正确使用 curl --data-urlencode
【发布时间】:2014-10-05 21:24:24
【问题描述】:

我正在尝试优化我的代码,并且借用了一段特定的代码。我想删除 sed,这样我就不会在主循环中使用任何外部进程。

function sendMsg () {
value=$(echo $1 | sed 's/ /%20/g;s/!/%21/g;s/"/%22/g;s/#/%23/g;s/\&/%26/g;s/'\''/%28/g;s/(/%28/g;s/)/%29/g;s/:/%3A/g;s/\//%2F/g');
str="http://www.xxxx.com/api.ashx?v=1&k=$Key&a=send&w=$value";
curl -s $str;
}

为清楚起见,我已对此进行了编辑。 $value 只是在函数末尾通过 curl 命令转换为正确的 url 以进行输出。

虽然这工作得很好,但我最感兴趣的是尽可能快地处理它,如果可以的话,不要分叉到外部进程。

感谢到目前为止的 cmets!

我目前的情况是这样的:

function sendMsg () {
str="http://www.xxxx.com/api.ashx?v=1&k=$Key&a=send&w=";
curl -s $str --data-urlencode "$1";
}

我至少在正确的轨道上吗?

【问题讨论】:

  • 是的,在 bash 中会更快。尽管 bash-the-language 很慢,但启动一个子进程、读取它的输出并等待()它退出的速度比几十个参数扩展要慢得多,
  • ...微基准测试(在循环中执行任一方法)将是回答这个问题的综合方法,你知道。
  • ...也就是说,如果您的目标是实现对任意数据的正确转义以用于形成 URL,我认为正确的答案不是 sed 参数扩展,但要使用规范实现,其他人多年来一直在棘手的极端情况下进行测试——例如 Python 的 urllib.quote()
  • 你应该考虑过--data-urlencode
  • @yab 你的问题已经和上一个完全不同了。我认为您应该刚刚接受修复它并创建另一个问题的当前答案。

标签: bash optimization curl sed


【解决方案1】:

首先,回答你的问题:如果你做的是单次替换或过滤,使用模式匹配会更快:

$ foo=${bar/old/new}               # Faster
$ foo=$(sed 's/old/new/' <<<$bar   # Slower

第一个不需要生成子 shell 并运行 sed,然后将其替换回 $foo。但是,如果你这样做了差不多十几次,我相信使用sed 可能会更快:

value=$(sed -e 's/ /%20/g' \
   -e 's/!/%21/g' \
   -e 's/"/%22/g' \
   -e 's/#/%23/g' \
   -e 's/\&/%26/g' \
   -e 's/'\''/%28/g' \
   -e 's/(/%28/g' \
   -e 's/)/%29/g' \
   -e 's/:/%3A/g' \
   -e 's/\//%2F/g'<<<$1);

请注意,此语法更易于阅读,因为每个替换命令都在自己的行中。另请注意,&lt;&lt;&lt; 消除了回显和管道的需要。

这只会对sed 进行一次调用,而模式匹配必须进行多次。

但是,您应该使用 --data--data-uuencode 而不是自己构建查询字符串:

$ curl -s http://www.xxxx.com/api.ashx \
    --data v=1 \
    --data k=$Key \
    --data a=send \
    --data-urlencode w="$value";

--data--urlencode 将为您编码$value 的值,因此您不必这样做。不幸的是,这个参数并不存在于curl 的所有版本中。它是在 2008 年 1 月的 7.18.0 版本中添加的。运行 curl --version 以查看您拥有的版本:

$ curl --version     # Life is good
curl 7.30.0 (x86_64-apple-darwin13.0) libcurl/7.30.0 SecureTransport zlib/1.2.5

$ curl --version     # David Sad
curl 7.15.5 (x86_64-redhat-linux-gnu) libcurl/7.15.5 OpenSSL/0.9.8b zlib/1.2.3 libidn/0.6.5

附录

在尝试此操作时,我得到一个“不支持的 API 版本错误”,即使我的 curl --version 报告 7.29.0

我无法测试您拥有的内容,但我决定尝试我们的 Jenkins 服务器,看看是否可以设置构建描述。我确保描述中有空格,所以它需要--data-urlencoding。该命令有效:

$ curl --user dweintraub:swordfish \
    --data Submit=Submit \
    --data-urlencode description="This is my test descripition" \
    http://jenkins.corpwad.com/jenkins/job/Admin-5.1.1/138/submitDescription

这就像我做的那样:

$ curl -user "dweintraub:swordfish http://jenkins.corpwad.com/jenkins/job/Admin-5.1.1/138/submitDescription?Submit=Submit&desciption=This%20is%20my%20test%20descripition"

请注意,--data 会为您添加问号。

(不,swordfish 不是我的密码)。

它不像您的命令那么复杂,但它可能有助于指出您遇到问题的地方。你有用户名和密码吗?如果是这样,您需要--user 参数。

【讨论】:

  • 在尝试此操作时,我得到一个“不支持的 API 版本错误”,即使我的 curl --version 报告 7.29.0
  • 其实是错误:不支持的API版本。我还在调查。
  • curl 7.29.0 (x86_64-pc-linux-gnu) libcurl/7.29.0 OpenSSL/1.0.1c zlib/1.2.7 libidn/1.25 librtmp/2.3 Protocols: dict file ftp ftps gopher http https imap imaps ldap ldaps pop3 pop3s rtmp rtsp smtp smtps telnet tftp Features: GSS-Negotiate IDN IPv6 Largefile NTLM NTLM_WB SSL libz TLS-SRP
  • 看起来这是我要发布到的服务器返回的消息。我仍在调查 curl 的输出,看看它是否与我原来的示例有任何不同。使用 --data 是否添加“?”在“xxxx.com/api.ashx”之后?
  • 见我的附录。有一个我使用的命令示例。 --data 为您添加 ?
【解决方案2】:

如果您必须经常这样做,生成多个sed 进程的开销可能会增加。在这种情况下,您可以改用以下行:

value=${1// /%20/}
value=${value//!/%21}
value=${value//\"/%22}
value=${value//\#/%23}
value=${value//&/%26}
value=${value//\'/%27}
value=${value//(/%28}
value=${value//)/%29}
value=${value//:/%3A}
value=${value//\//%2F}

【讨论】:

  • 这会比弄清楚如何使用 curl 和 --data-urlencode 选项更快吗? (顺便说一句,我也迷路了:P)
  • 如果适用的话,使用--data-urlencode 会更快(并且维护起来也更简单),所以我会花时间进行调查。
猜你喜欢
  • 2019-06-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-07-21
  • 1970-01-01
相关资源
最近更新 更多