我正在尝试制作一个 bash 脚本,该脚本循环遍历包含文件列表的文件(因此它会遍历每个文件)。当文件打开时,我想使用另一个程序 (jq) 从 JSON 文件的键值对中提取值。这是我到目前为止正在处理的内容,保持非常基本,这样我就可以尝试找出哪里出错了。我不关心 jq 命令,我已经让它工作了,我可以循环遍历所有文件并提取单个键的值,但这最终变得非常乏味,因为我必须手动更改它对于每个键。
长话短说: “master” 是包含我想要打开的每个 JSON 文件的完整路径的文件。“key.txt” 是包含这些 JSON 文件中所有可能键的文件。$KEY 是 jq 的语法,用于在打开的文件中搜索该特定键并返回该键的值。我想打开主列表中的文件,循环遍历所有可能的键,并将这些键的值返回到名为“list.txt”的文本文件中。
任何帮助将不胜感激。
#!/bin/bash
master="path/masterlist.txt"
while read master
do
for KEY in 'key.txt'
do
jq '. .'$KEY'' $f
echo $KEY
done >> list.txt
echo $master
done < list.txt
答案1
这是我在获得更多经验后重新审视旧答案jq
。
问题中的用户说
我不关心 jq 命令 [...]
...但事实上,jq
命令是让这项工作高效进行的关键。
回顾一下:用户想要提取某个文本文件 .txt 中列出的所有键的所有值keys.txt
。他们希望对另一个文件 .txt 中列出的所有 JSON 文件执行此操作list.txt
。
要使用 、 、、、 从一组文件 、、 、 中获取一组键 、a
、b
、的所有(已解码)值,您可以这样做:c
file1
file2
file3
jq
jq -r '.[$ARGS.positional[]] // empty' file1 file2 file3 --args a b c
这会将用作键的字符串传递给jq
,后者接受它们作为数组中的元素$ARGS.positional
。该数组被扩展,其元素用作从输入获取值的键。在这里,empty
如果键的值不存在或为,我选择不返回任何内容 ( ) null
。
围绕该操作内核添加 shell 管道,假设文件列表和键列表都可以是任意长,并且这两个文件包含根据需要引用的行:
xargs sh -c '
xargs jq -r ".[\$ARGS.positional[]] // empty" "$@" --args <keys.txt
' sh <list.txt >result.txt
这将获取文件名列表并调用一个简短的内联 shell 脚本来批量处理这些文件。内联脚本使用给定的文件名 ( ) 和从键列表中读取的键集xargs
进行调用。jq
"$@"
结果值列表被写入result.txt
。
旧答案如下:
阅读完您说您想做的事情后:
master="path/masterlist.txt"
while read json_path; do
while read key; do
printf 'File="%s", Key="%s"\n' "$json_path" "$key"
jq ". .'$key'" "$json_path"
done <key.txt
done <"$master" >list.txt
读取 JSON 文件列表并依次$master
分配每个路径。json_path
key.txt
在内循环中,依次读取和分配键key
。该实用程序通过参数jq
调用,其中参数用当前键的值进行扩展。$json_path
. .'$key'
$key
所有输出都放入list.txt
.
内部循环可能需要进行一些优化。例如,似乎没有必要在外循环的每次迭代中读取所有键。
脚本的带注释版本:
master="path/masterlist.txt" # this is never used
while read master # this will set $master to something from list.txt
do
for KEY in 'key.txt' # $KEY will be the string 'key.txt' (nothing else)
do
jq '. .'$KEY'' $f # $f is empty
echo $KEY
done >> list.txt # better to >list.txt after "done" of outer loop
echo $master
done < list.txt # you probably don't want to read from this file
答案2
通过阅读您发布的脚本,我认为$f
分配不正确。此外,命令中的引用jq
可能会导致问题。事实上,您正在尝试在 while 循环中读取一个裸字,该循环也可能在尝试将其追加到循环内部的同时尝试master
读入。list.txt
list.txt
#!/bin/bash
master="path/masterlist.txt"
cat $master | while read f; do
for KEY in 'key.txt'; do
echo $(jq ". .'$KEY'" $f) >> list.txt
done
echo $master
done
这将从文件中获取每一行,并将其分配给循环中的$master
变量,然后运行查询,将输出附加到.$f
jq
list.txt