Bash、curl、eval 和空格
我正在编写一个脚本来针对给定的用户输入执行 CURL 命令。该脚本有多个辅助函数来创建最终将传递给 CURL 的参数(参数)列表。
一个精简的示例如下:
#!/bin/bash
function create_arg_list
{
# THIS HTTP HEADER VALUE COMES FROM THE USER and MAY CONTAIN SPACES
local __hdr="x-madhurt-test:madh urt"
local __params="http://google.co.in -X GET -H '$__hdr'"
local __resultvar="$1"
eval $__resultvar="\"$__params\""
echo "params after eval : $__resultvar"
}
create_arg_list arg_list
echo "params after eval in main code : $arg_list"
echo "Running command : curl -v $arg_list"
curl -v $arg_list
当输入参数(文件路径、url 等)中包含(引用的)空格时,脚本效果很好。但是,当应该作为 HTTP 标头传递给 CURL 的参数包含空格时,脚本会严重失败。
这是我尝试过的:
- 在标题值周围使用单引号(例如“$__hdr”)。但是,传递给 CURL 的值是:
curl -v http://google.co.in -X GET -H 'x-madhurt-test:madh urt'
,它被 CURL 视为 as-as,发送的实际标头如下:'x-madhurt -test:madh
- 对标头值进行双重转义(例如 \\"$__hdr\\"),但这似乎也有效。在这种情况下,CURL 将“urt”作为单独的参数并将其视为 URL
curl: (6) Couldn't parse host 'urt"'
- 转义标头值中的空格(即使用“ madh\ urt”而不是“madh urt”),但这与选项 2 相同。
有人知道这里发生了什么错误吗?
I'm writing a script to execute CURL commands for a given user input. The script has multiple helper function to create the list of parameters (arguments) that will eventually be passed to CURL.
A stripped out example, is as follows :
#!/bin/bash
function create_arg_list
{
# THIS HTTP HEADER VALUE COMES FROM THE USER and MAY CONTAIN SPACES
local __hdr="x-madhurt-test:madh urt"
local __params="http://google.co.in -X GET -H '$__hdr'"
local __resultvar="$1"
eval $__resultvar="\"$__params\""
echo "params after eval : $__resultvar"
}
create_arg_list arg_list
echo "params after eval in main code : $arg_list"
echo "Running command : curl -v $arg_list"
curl -v $arg_list
The script works great when the input parameters (file path, url etc..) have (quoted) white space in them. However, when the arguments that are supposed to be passed as HTTP Headers to CURL contain spaces, the script fails miserably.
Here is what I've tried :
- Use single quotes around the header value (e.g. '$__hdr'). However, with this the value that is passed to CURL is :
curl -v http://google.co.in -X GET -H 'x-madhurt-test:madh urt'
, which is treated as-as by CURL and the actual header that is sent is like this :
'x-madhurt-test:madh
- Double escape the header value (e.g. \\"$__hdr\\"), but this does seem to work as well. In this case CURL gets "urt" as a separate parameter and treats it as a URL
curl: (6) Couldn't resolve host 'urt"'
- Escape the space in the header value (i.e. use "madh\ urt" instead of "madh urt"), but this turns out to be the same as option 2.
Does someone have insights as to what is happening wrong here?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
该代码可以工作,但并不打算按原样使用。我发布它是为了给您一些如何继续的想法。使您想要做的事情发挥作用的关键是使用数组。不幸的是,Bash 无法从函数返回数组。您可能应该做的是使用全局数组。但是,下面的代码从
declare
语句创建一个字符串,并将其传递给间接变量。这是一个非常糟糕的混乱。This code works but it's not intended to use as-is. I'm posting it to give you some ideas for how you might proceed. They key to making what you want to do work is to use an array. Unfortunately, Bash can't return arrays from functions. What you probably ought to do is use a global array. The code below, however, creates a string out of a
declare
statement and passes that through your indirect variable. It's a seriously bad kludge.丹尼斯的回答很好,所以我将重点讨论为什么你的代码不起作用。让我们使用辅助函数来显示函数接收的参数:
好的,正如预期的那样,引号仅用于分隔参数。但现在让我们像您一样使用变量:
Bash 扩展变量并且函数(或命令)获取引号。当然,这不是你想要的。
解决方案1:使用eval重新解释引号。
解决方案2:使用一个数组并用“${MYARRAY[@]}”扩展它,如 Dennis 所示。
更多想法:我有时使用的一种技术是在外部进行评估:
在这种情况下,otherfun 将返回一个字符串,在评估时,将创建一个名为 VARNAME 的变量(甚至可以是本地变量)。该变量(或多个变量,如果需要)可以是字符串或数组。同样,我将使用一个数组,以便以后可以轻松使用它:
Dennis's answer is good, so I'll focus on why your code does not work. Let's use an auxiliar function to show the arguments received by a function:
Ok, as expected the quotes are solely used to delimit arguments. But now let's use a variable as you did:
Bash expands the variable and the function (or command) gets the quotes. That's not what you wanted, of course.
Solution1: Use eval to re-interpret quotes.
Solution2: Use an array and expand it with "${MYARRAY[@]}" as Dennis showed.
More ideas: a technique I've sometimes used is doing the eval outside:
In this case otherfun would return a string that, when evaled, would create a variable with name VARNAME (that can be even local). This variable (or variables, if needed) can be string or arrays. Again, I'd use an array so it can be easily used afterwards: