jq使用外部文件作为--arg参数值
2021-10-24 本文已影响0人
CodingCode
-
jq --arg DATA "$(<data.txt)"
-
jq --argjson DATA "$(<data.json)"`
-
jq --rawfile data.txt
-
jq --slurpfile data.json
- 文件包含文本(字符串数据)
- 方法 1:
--arg DATA "$(<data.json)"
$ jq --arg DATA "$(<data.txt)" ...
举例来说:
$ cat data.txt
abcd
$ echo '{"payload":{"data":{"update":null}}}' | jq --arg DATA "$(<data.txt)" '.payload.data.update = $DATA'
{
"payload": {
"data": {
"update": "abcd"
}
}
}
注意"$(<data.txt)"
要加双引号,因为这个实际是shell的语法,不是jq的语法:
- shell读取文件data.txt的内容,拼成字符串再传给jq,所以jq拿到的就是字符串了。
- 如果是单引号,则shell不会去解析文件读取操作,会把命令本身(
$(<data.txt>
)作为字符串传给jq。
$ echo '{"payload":{"data":{"update":null}}}' | jq --arg DATA '$(<data.txt)' '.payload.data.update = $DATA'
{
"payload": {
"data": {
"update": "$(<data.txt)"
}
}
}
- 如果没有引号,那么当data.txt内容含有特殊符号,例如空格,换行符之类时,整个jq命令解释就会失败(这实际上还是shell无法解析命令行)。
$ cat data.txt
line1-1 line1-2
line2
$ # without double-quote
$ echo '{"payload":{"data":{"update":null}}}' | jq --arg DATA $(<data.txt) '.payload.data.update = $DATA'
jq: error: line1/0 is not defined at <top-level>, line 1:
line1-2
jq: 1 compile error
$ # with double-quote
$ echo '{"payload":{"data":{"update":null}}}' | jq --arg DATA "$(<data.txt)" '.payload.data.update = $DATA'
{
"payload": {
"data": {
"update": "line1-1 line1-2\nline2"
}
}
}
- 方法2:使用参数--rawfile
还用前面的例子:
$ echo '{"payload":{"data":{"update":null}}}' | jq --rawfile DATA data.txt '.payload.data.update = $DATA'
{
"payload": {
"data": {
"update": "abcd\n"
}
}
}
看到这和方法1有区别,它把文件的最后一个换行符读出来了,作为文本的内容了。这其实都是shell的功能在起作用。
- 语法$(<data.txt>)十八data.txt作为文本文件读取,自动忽略最后的文件结束符。
- --rawfile是读取整个文件的内容,不管啥字符,是raw格式嘛。所以遇到这个情况就需要事先把文件的最后一个结束符先删除(例如,命令
$ truncate -s-1 data.txt
)。
说道这儿了,咱们就整一个二进制的文件看看两者区别是什么?
$ hexdump -C data.txt
00000000 7f 45 4c 46 02 01 01 00 00 00 |.ELF......|
0000000a
$ echo '{"payload":{"data":{"update":null}}}' | jq --rawfile DATA data.txt '.payload.data.update = $DATA'
{
"payload": {
"data": {
"update": "\u007fELF\u0002\u0001\u0001\u0000\u0000\u0000"
}
}
}
$ echo '{"payload":{"data":{"update":null}}}' | jq --arg DATA "$(<data.txt)" '.payload.data.update = $DATA'
{
"payload": {
"data": {
"update": "\u007fELF\u0002\u0001\u0001"
}
}
}
看到,"$(<data.txt)"
格式把文本里面的字符'\0'自动过滤掉了呢。
- 文件包含json子串
- 方法1:
--argjson DATA "$(<data.json)"
$ cat data.json
{ "name": "Tom", "age": 30}
$ echo '{"payload":{"data":{"update":null}}}' | jq --argjson DATA "$(<data.json)" '.payload.data.update = $DATA'
{
"payload": {
"data": {
"update": {
"name": "Tom",
"age": 30
}
}
}
}
- 方法2:使用参数--slurpfile
$ echo '{"payload":{"data":{"update":null}}}' | jq --slurpfile DATA data.json '.payload.data.update = $DATA'
{
"payload": {
"data": {
"update": [
{
"name": "Tom",
"age": 30
}
]
}
}
}
两者有啥区别呢,好像没啥区别?
你仔细看了,再仔细看!
两者区别大了。--slurpfile
方式update的值变成数组([...]
)了哦。
jq的文档(https://stedolan.github.io/jq/manual/)说的非常明确:
* --slurpfile variable-name filename:
This option reads all the JSON texts in the named file and
binds an array of the parsed JSON values to the given global variable.
If you run jq with --slurpfile foo bar, then $foo is available in the program and
has an array whose elements correspond to the texts in the file named bar.
所以在这个场景里,我们需要用下标$DATA[0]
来指示:
$ echo '{"payload":{"data":{"update":null}}}' | jq --slurpfile DATA data.json '.payload.data.update = $DATA[0]'
{
"payload": {
"data": {
"update": {
"name": "Tom",
"age": 30
}
}
}
}
所以--slurpfile可以支持文件是多个数据的格式:
$ cat data.json
{ "name": "Tom", "age": 30}
{ "name": "Jerry", "age": 30}
{
"name": "Mick",
"age": 40
}
$ echo '{"payload":{"data":{"update":null}}}' | jq --slurpfile DATA data.json '.payload.data.update = $DATA'
{
"payload": {
"data": {
"update": [
{
"name": "Tom",
"age": 30
},
{
"name": "Jerry",
"age": 30
},
{
"name": "Mick",
"age": 40
}
]
}
}
}
这里data.json的内容不是一个标准的json数据,不是数组类型,也不是map类型,不伦不类;所以(jq --argjson DATA "$(<data.txt)")
格式就无法支持这种。