使用多行JSON格式的Curl

158

考虑下面的curl命令,是否有可能允许在JSON中使用换行符(而不需要缩小)并直接在bash(Mac / Ubuntu)中执行?

curl -0 -v -X POST http://www.example.com/api/users \
-H "Expect:" \
-H 'Content-Type: text/json; charset=utf-8' \
-d \
'
{
    "field1": "test",
    "field2": {
        "foo": "bar"
    }
}'
当我运行上述命令时,似乎出现了错误在第二个 {。如何修复上述命令? 更新:实际上我之前能够成功运行该命令,不确定最近出现了什么问题。

2
你能告诉我们更多关于错误的信息吗?在我的系统上,你的示例代码可以“原样”运行。mymac > bash --version GNU bash, version 3.2.57(1)-release (x86_64-apple-darwin15) Copyright (C) 2007 Free Software Foundation, Inc. - Eric Bolinger
没错,这对我也有效:GNU bash,版本4.3.42(1)-release - miken32
3
请参考类似ANSI C的字符串语法echo $'这里是换行符:\n这里是制表符:\t' - miken32
1
application/json 是 JSON 数据的正确媒体类型 -- 请参阅 RFC4627 - Pocketsand
7个回答

215

我记得在Bash man页面和这里详细介绍中提到了一种使用"Here Document"的方法。"@-"表示从STDIN读取正文,而"<< EOF"表示将脚本内容作为STDIN管道传递到curl直到遇到"EOF"。这种布局可能比使用单独文件或"echo变量"方法更易于阅读。

curl -0 -v -X POST http://www.example.com/api/users \
-H "Expect:" \
-H 'Content-Type: application/json; charset=utf-8' \
--data-binary @- << EOF
{
    "field1": "test",
    "field2": {
        "foo": "bar"
    }
}
EOF

注意: 使用--trace <outfile> curl 选项记录网络传输的详细信息。由于某些原因,使用这种文件输入方法会删除换行符。(更新:换行符被curl -d选项删除了。已更正!)


6
这很干净,没有额外的引用,也没有转义,并且非常有效。谢谢。 - Seth
1
我们可以使用这样的语法来使用管道吗? - Ivan Balashov
3
是的,你可以将输出导入到另一个命令中,尽管位置正好处于中间。在 stdin 重定向之后添加 stdout 重定向。下面是一个使用单词计数示例:-d @- << EOF | wc - Eric Bolinger
2
这不是 Here Document 去除换行符,而是使用 curl -d 选项:https://curl.haxx.se/docs/manpage.html#-d。使用 --data-binary 保留换行符和回车符号。 - dzieciou
1
你一定可以插入变量!看看当你将"foo": "bar"替换为"$SHELL": "$(date)"时会发生什么。 - Eric Bolinger
显示剩余3条评论

58
沿着马丁的建议,将JSON放入变量中,您还可以将JSON放入单独的文件中,然后使用curl的@语法提供文件名将其提供给-d
curl -0 -v -X POST http://www.example.com/api/users \
  -H "Expect:" \
  -H 'Content-Type: text/json; charset=utf-8' \
  -d @myfile.json

缺点很明显(你以前只有一个文件,现在却有两个或更多)。但是好的一面是,你的脚本可以接受文件名或目录参数,你永远不需要编辑它,只需在不同的JSON文件上运行即可。这是否有用取决于你想要实现什么。


1
注意:请确保您通过 https://jsonlint.com/ 获得有效的 JSON 内容。 - vikramvi
与其他方法相比,这种方法更加简洁易懂,并且容易调试。 - vikramvi
很棒的解决方案。但要小心 PATH! - Pierre Ferry

36

由于某些原因,这种Here Document方法会剥离换行符

@eric-bolinger Here Document去掉换行符的原因是因为您需要使用EOF来引用您的Here Document以保留换行符:

curl -0 -v -X POST http://www.example.com/api/users \
-H "Expect:" \
-H 'Content-Type: text/json; charset=utf-8' \
-d @- <<'EOF'

{
    "field1": "test",
    "field2": {
        "foo": "bar"
    }
}
EOF

注意第一次定义EOF时周围有单引号,但第二次没有。


30

您应该使用外层双引号,并转义所有内部引号,如下所示:

curl -0 -v -X POST http://www.example.com/api/users \
-H "Expect:" \
-H 'Content-Type: text/json; charset=utf-8' \
-d \
"
{
    \"field1\": \"test\",
    \"field2\": {
        \"foo\": \"bar\"
    }
}"

28

你可以将json赋值给一个变量:

json='
{
    "field1": "test",
    "field2": {
        "foo": "bar"
    }
}'

现在你可以使用 stdin 将此转发给 curl:

echo $json | curl -0 -v -X POST http://www.example.com/api/users \
-H "Expect:" \
-H 'Content-Type: text/json; charset=utf-8' \
-d @-

1
使用单引号来包围代码块意味着您不能在JSON中使用变量(例如${username})。 - Air
1
是的,但使用双引号意味着您无法在数据中使用$符号。选择适合您的选项。 - Martin Konecny

10

我认为这可以作为一个答案。

curl -0 -v -X POST http://www.example.com/api/users \
-H "Expect:" \
-H 'Content-Type: text/json; charset=utf-8' \
--data-raw '
{
    "field1": "test",
    "field2": {
        "foo": "bar"
    }
}'

我喜欢这个,因为它即使在缩进的情况下也能很好地工作,而且如果使用""引号,甚至可以使用变量。 - lnksz

0

最近我在使用curl传输多行JSON数据时遇到了困难。以上的解决方案都没有对我起作用,但是我通过在“-d”参数中使用“@-”从stdin读取数据来解决了这个问题。在stdin中,我使用“BODY”关键字定义了JSON主体。

    curl \
    -X POST http://www.example.com/api/users \
    -H 'Content-Type: application/json' \   
    -d @- <<BODY
    {
      "field1": "test",
      "field2": {
        "foo": "bar"
      }
    }
    BODY

这个链接帮助我理解了不同的curl参数的含义。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接