如何在bash脚本中执行存储在heredoc中的curl命令?

Posted

技术标签:

【中文标题】如何在bash脚本中执行存储在heredoc中的curl命令?【英文标题】:How to execute curl command stored in heredoc in bash script? 【发布时间】:2021-12-14 23:24:07 【问题描述】:

在编写 bash 脚本时,我想将整个 curl 命令存储在 heredoc 中以获得更好的布局。以下工作正常:

#/bin/bash

read -r -d '' command1 <<- MULTI_STRING_SCOPE
  curl -v www.***.com
MULTI_STRING_SCOPE

但是当使用-d 选项添加一些json数据时,该命令的执行很奇怪。例如:

#/bin/bash

read -r -d '' command2 <<- MULTI_STRING_SCOPE
  curl -v www.***.com
    -d '
      "hello":"world"
    '
MULTI_STRING_SCOPE
response2=$($command2)

来自终端的错误日志:

curl: (3) URL using bad/illegal format or missing URL
curl: (3) unmatched close brace/bracket in URL position 1:
'

而且似乎 curl 将 ' 行作为单独的 url,因此 json 数据没有作为一个单元发送。

如何解决问题?任何建议都将受到高度赞赏。

【问题讨论】:

将命令存储为字符串是个坏主意;它可能会使布局更好,但解析是一团糟。基本上,变量用于存储数据,而不是可执行代码。请参阅BashFAQ #50: I'm trying to put a command in a variable, but the complex cases always fail! 在这种情况下,我强烈建议使用函数而不是变量。 (注意:有些人推荐 eval 来处理这样的事情,但这只会引发新的解析混乱。这样会带来疯狂和非常奇怪的错误。) @GordonDavisson 这真的很重要。我曾经了解过data and command 的故事,但我只是不知道自己陷入了这种境地。谢谢你的提示。 【参考方案1】:

我从 this post 那里学到了如何让 heredoc 使用 curl 命令。

正如@Gordon Davisson 在当前帖子中发表的评论,我们不应该将命令与数据混为一谈。由于json数据设置为-d选项只有数据,其他部分是命令,所以我决定使用heredoc只存储json数据,其他部分保留为命令本身,而不是通过@将它们存储在字符串中987654325@.

结果 bash 脚本应该是这样的:

#/bin/bash

response3=$(curl -v www.***.com \
  -d @- <<- MULTI_STRING_SCOPE
        
            "hello":"world"
        
    MULTI_STRING_SCOPE
  )

注意:heredoc indent 仅适用于制表符,不适用于空格。请小心,尤其是当您使用像 Visual Studio Code 这样的编辑器时,它们可能已经为您设置了缩进为空白。

【讨论】:

这里的文档在这里提供了什么实际价值呢?只传入一个多行字符串不是更简单明了吗? @tripleee 对于我上面给出的情况,这里的文档不是必需的。在我的实际情况下,我需要使用“-d”选项以 json 格式发送数据,同时将变量替换为该 json 数据。因为json里面的双引号太多了,所以我选择-d '"json":"data"'跟单引号一起工作,而单引号里面的变量替换好像不行,所以我转向here document。这样有意义吗,或者也可以通过简单的多行字符串来实现? 您不能在单引号内进行变量替换。对于这种情况,here 文档实际上并不是一个糟糕的解决方案;其他解决方案包括“跷跷板引用”,如'"key" :"'"$value"'"'(这就像用反斜杠转义所有文字双引号一样混乱)或使用像sed 这样的外部实用程序来替换静态字符串或文档中的占位符。 我学到了很多,谢谢@tripleee

以上是关于如何在bash脚本中执行存储在heredoc中的curl命令?的主要内容,如果未能解决你的问题,请参考以下文章

如何使 cat 和 grep 在 c 中的第一个和第二个管道中工作,就像 bash 中的 heredoc <<

在heredocs中着色,bash

Bash Heredoc 格式在 ) 末尾添加新行;

睡眠后如何使用heredoc发送一些输入?

通过 SSH 执行存储在文件中的 Bash 脚本

bash中的heredoc里面的范围,我的$ PORT变量不起作用