使用 jq 和 bash 为数组中的每个对象运行命令

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/43192556/
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-18 15:58:23  来源:igfitidea点击:

Using jq with bash to run command for each object in array

bashjq

提问by danielrvt

How can I run a bash command for every json object in a json array using jq? So far I have this:

如何使用 jq 为 json 数组中的每个 json 对象运行 bash 命令?到目前为止,我有这个:

cat credentials.json | jq -r '.[] | .user, .date, .email' | mycommand -u {user} -d {date} -e {email}

This doesn't seem to work. How can I take the parameters out of the json array into my command?

这似乎不起作用。如何将参数从 json 数组中取出到我的命令中?

My json file looks something like this:

我的 json 文件看起来像这样:

[
   "user": "danielrvt",
   "date": "11/10/1988",
   "email": "[email protected]",
   ...
]

回答by chepner

Your best bet is probably to output each record in something like TSV format, then read that from a shell loop.

您最好的选择可能是以类似 TSV 格式的格式输出每条记录,然后从 shell 循环中读取它。

jq -r '.[]|[.user, .date, .email] | @tsv' |
  while IFS=$'\t' read -r user date email; do
    mycommand -u "$user" -d "$date" -e "$email"
  done

jqitself doesn't have anything like a systemcall to run an external command from within a filter, although it seems that they are working on it.

jq本身没有任何类似system调用从过滤器内运行外部命令的功能,尽管它们似乎正在处理它

回答by kojiro

You could have jqoutput the commands to execute, something like

您可以jq输出要执行的命令,例如

.[] | "mycommand \(.user|@sh) \(.date|@sh) \(.email|@sh)"

Then execute it. Something like

然后执行它。就像是

bash <(jq -r '.[] | "mycommand \(.user|@sh) \(.date|@sh) \(.email|@sh)"' foo)

回答by Marcin

With xargs:

使用 xargs:

curl localhost:8082/connectors | jq .[] | xargs -L1 -I'{}' curl -XDELETE 'localhost:8082/connectors/{}' 

Or equivalently, to show the output of that first curl:

或者等效地,显示第一个 curl 的输出:

echo '["quickstart-file-sink4","quickstart-file-source","quickstart-file-sink","quickstart-file-sink2","quickstart-file-sink3","quickstart-file-source2"]' | jq .[] | xargs -L1 -I'{}' curl -XDELETE 'localhost:8082/connectors/{}' 

jq .[]strips off one level of containment, so that a list becomes output as one line per item.

jq .[]剥离一层包含,以便列表成为每个项目一行的输出。

xargs -L1processes one line at a time

xargs -L1一次处理一行

xargs -I'{}'specifies that the string {}be replaced with the input line when invoking the following command.

xargs -I'{}'指定{}在调用以下命令时将字符串替换为输入行。

xargsis essentially a map operator for the shell.

xargs本质上是外壳的映射运算符。

回答by Haochen Xie

I came across the same problem recently where xargs doesn't help that much due to the relatively complicated set of arguments I wanted to pass around. Thus I implemented an shfilter (and its friends) to jq. I haven't yet had enough time to write documentation and tests for it so not creating a PR for it to become a part of the official codebase yet. So now it's only for the ones who are willing to compile this version themselves:

我最近遇到了同样的问题,由于我想传递的一组相对复杂的参数,xargs 没有太大帮助。因此,我sh为 jq实现了一个过滤器(及其朋友)。我还没有足够的时间为其编写文档和测试,因此还没有为其创建 PR 使其成为官方代码库的一部分。所以现在只给那些愿意自己编译这个版本的人:

https://github.com/haochenx/jq/tree/sh-support

https://github.com/haochenx/jq/tree/sh-support

回答by Chris Gibb

Here is another variation which I based on the answer from @chepner.

这是我基于@chepner 的回答的另一种变体。

echo "$config" | jq -c '.[]' |
while IFS=$"\n" read -r c; do
    echo "start"
    host=$(echo "$c" | jq -r '.host')
    echo $host
    echo "end"
done

I used jq's -c option to output "compact" jsons, so they are all on one line.

我使用 jq 的 -c 选项输出“紧凑”json,所以它们都在一行上。

In combination with IFS=$"\n", I was able to loop over each item in the input json's array and do what I wanted to do.

与 结合使用IFS=$"\n",我能够遍历输入 json 数组中的每个项目并做我想做的事情。

So, with an input of

所以,输入

[
 {
  "host": "host1",
  "settings": {}
 },
 {
  "host": "host1",
  "settings": {}
 }
]

the output is

输出是

start
host1
end
start
host2
end