我正在尝试编写一个名为jq_select_keys
的fish函数,该函数从给定的JSON中选择键的子集。
做这件魔术的jq咒语是:
jq -r "with_entries(select([.key] | inside([\"bar\",\"baz\",\"qux\"])))" file.json
现在,我正在尝试定义一个名为jq_select_keys的便捷函数,该函数将使用我感兴趣的文件名和键,然后吐出子集。这是我想出的:
function jq_select_keys --description 'Selects given keys from json input'
set key_names (for key in $argv[2..-1]; echo "\\\"$key\\\""; end)
set key_names_joined (string join "," $key_names)
set jq_args "\"with_entries(select([.key] | inside([$key_names_joined])))\""
echo "Command: jq -r $jq_args $argv[1]"
jq -r $jq_args $argv[1]
end
在鱼壳上运行jq_select_keys foo.json bar baz qux
时,得到以下输出:
Command: jq -r "with_entries(select([.key] | inside([\"bar\",\"baz\",\"qux\"])))" foo.json
with_entries(select([.key] | inside(["bar","baz","qux"])))
现在,有趣的是,我可以复制粘贴echo语句的输出,并且它可以按预期运行。但是我得到的输出只是我传递给jq的查询字符串。
我是Shell编程的新手,所以我可能把报价弄乱了。但是除此之外,我不知道如何使这个东西正常工作!
答案 0 :(得分:5)
我是Shell编程的新手,所以我可能把报价弄乱了。
基本上就是这样。
您似乎增加了一层引号。
在鱼(以及大多数其他壳,包括bash和zsh)中,引号仅在按字面使用时对壳而言是特殊的。
这意味着当变量包含"some string"
时,echo $variable
将显示"some string"
-这意味着echo
命令收到带有引号的字符串 (注意:bash在这里也会应用分词,因此即使您可能会引用它,它实际上也会收到"some
和string"
)。
我建议您一个接一个地浏览函数,并简单地echo
变量。然后想象您将那个确切的字符串传递给了jq
-可以吗?
例如$key_names
位:
set key_names (for key in $argv[2..-1]; echo "\\\"$key\\\""; end)
显然,此操作的目的是转义所有与jq
一起使用的键(从第二个开始为参数)。这意味着它们必须被一次引用。无需再次引用它们,因为外壳不关心非文字引号。
因此任何键都应类似于"key"
。
但是当我们放进去
printf '%s\n' $key_names
(它将在每个行上打印每个键)
在此之后,我们看到
\"bar\"
\"baz\"
\"qux\"
那是两层的报价!引号本身,反斜杠转义。
所以我们删除一个:
设置key_names(用于$ argv [2 ..- 1]中的密钥;回显“ \” $ key \“”;结束)
这将导致"bar"
,"baz"
和"qux"
。
(这可以通过使用fish的cartesian product简化为set key_names \"$argv[2..-1]\"
)
现在下一位:
set jq_args "\"with_entries(select([.key] | inside([$key_names_joined])))\""
您的意图是像执行此操作一样
jq -r "with_entries(select([.key] | inside([\"bar\",\"baz\",\"qux\"])))" foo.json
在命令行上。但是,当您使用变量时,无需在引号中再次使用字符串-分配值后,所有拆分和其他扩展操作都已经发生,而替换变量时不再发生。
因此只需删除转义的引号
set jq_args "with_entries(select([.key] | inside([$key_names_joined])))"
您的功能应该正常工作。
结果是:
function jq_select_keys --description 'Selects given keys from json input'
set key_names \"$argv[2..-1]\"
set key_names_joined (string join "," $key_names)
set jq_args "with_entries(select([.key] | inside([$key_names_joined])))"
echo "Command: jq -r $jq_args $argv[1]"
jq -r $jq_args $argv[1]
end
答案 1 :(得分:2)
jq是有趣的野兽。我不知道为什么您的脚本只输出$ jq_args内容。
它具有--slurpfile选项,可将JSON字符串文件读入数组变量。这使您不必动态构造JSON数组和jq脚本主体
$ function jqs
jq -r --slurpfile keys (printf '"%s"\n' $argv[2..-1] | psub) \
'with_entries(select([.key] | inside($keys)))' $argv[1]
end
$ cat file.json
{"foo":"a","bar":"b","baz":"c"}
$ jqs file.json foo baz
{
"foo": "a",
"baz": "c"
}