Bash、curl、eval 和空格

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3187614/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-17 22:17:37  来源:igfitidea点击:

Bash, curl, eval and whitespace

bashscriptingcurlevalwhitespace

提问by madhurtanwani

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.

我正在编写一个脚本来为给定的用户输入执行 CURL 命令。该脚本有多个辅助函数来创建最终将传递给 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=""
 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.

当输入参数(文件路径、url 等)中有(引用)空格时,该脚本运行良好。但是,当应该作为 HTTP 标头传递给 CURL 的参数包含空格时,脚本会失败。

Here is what I've tried :

这是我尝试过的:

  1. 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
  2. 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"'
  3. 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.
  1. 在标题值周围使用单引号(例如'$__hdr')。但是,通过此传递给 CURL 的值是:
    curl -v http://google.co.in -X GET -H 'x-madhurt-test:madh urt'
    ,它被 CURL 视为原样,发送的实际标头如下所示:
    'x-madhurt-test:madh
  2. 对标头值进行双重转义(例如 \\"$__hdr\\"),但这似乎也有效。在这种情况下,CURL 将“urt”作为单独的参数并将其视为 URL
    curl: (6) Couldn't resolve host 'urt"'
  3. 转义标题值中的空格(即使用“madh\ urt”而不是“madh urt”),但结果与选项2相同。

Does someone have insights as to what is happening wrong here?

有人对这里发生了什么问题有见解吗?

采纳答案by Paused until further notice.

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 declarestatement and passes that through your indirect variable. It's a seriously bad kludge.

此代码有效,但不打算按原样使用。我发布它是为了给你一些关于如何继续的想法。使您想做的事情工作的关键是使用数组。不幸的是,Bash 不能从函数返回数组。您可能应该做的是使用全局数组。但是,下面的代码从declare语句中创建了一个字符串,并将其传递给您的间接变量。这是一个非常糟糕的混搭。

#!/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"
 __params=($__params "$__hdr")

 local __resultvar=""
 eval $__resultvar=$(printf "%q" "$(declare -p __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"

eval $arg_list

curl -v "${__params[@]}"

回答by tokland

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:

丹尼斯的回答很好,所以我将重点讨论为什么您的代码不起作用。让我们使用辅助函数来显示函数接收的参数:

$ args() { for x in "$@"; do echo $x; done }
$ args 1 '2 b' 3
1
2 b
3

Ok, as expected the quotes are solely used to delimit arguments. But now let's use a variable as you did:

好的,正如预期的那样,引号仅用于分隔参数。但是现在让我们像您一样使用一个变量:

$ var="1 '2 b' 3"
$ args $var
1
'2
b'
3

Bash expands the variable and the function (or command) gets the quotes. That's not what you wanted, of course.

Bash 扩展变量,函数(或命令)获取引号。当然,这不是你想要的。

Solution1: Use eval to re-interpret quotes.

解决方案 1:使用 eval 重新解释引号。

$ eval args $var
1
2 b
3

Solution2: Use an array and expand it with "${MYARRAY[@]}" as Dennis showed.

解决方案 2:使用一个数组并用 "${MYARRAY[@]}" 展开它,如丹尼斯所示。

More ideas: a technique I've sometimes used is doing the eval outside:

更多想法:我有时使用的一种技术是在外面做 eval:

$ eval "$(create_args_list VARNAME)"

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:

在这种情况下,otherfun 将返回一个字符串,当求值时,该字符串将创建一个名为 VARNAME 的变量(甚至可以是本地的)。此变量(或变量,如果需要)可以是字符串或数组。同样,我将使用一个数组,以便以后可以轻松使用它:

$ curl "${VARNAME[@]}"