我有一个文件,其中包含 ids:
123abc
456dbc
我想在迭代文件时将它们传递给命令。
目前,我的命令是这样工作的:part_of_command '{"id":{"S":"123abc"}}'
.但是,现在有了该文件,我想将 123abc 替换为文件每一行中的内容。
我正在尝试完成类似的事情:
while read line; do
command '{"id":{"S":"$line"}}'
done <output.txt
其中行是 123abc 或 456dbc 或任何其他 id。但 $line 给出单引号和双引号错误。知道如何解决这个问题吗?
答案1
您似乎想将嵌套的 JSON 对象作为参数传递给某个命令。 shell 不会扩展单引号内的变量。
不过,这里的解决方案不是改用双引号,因为注入 JSON 文档的数据可能需要编码才能成为有效的 JSON(如果它包含制表符、引号或其他会破坏格式的字符) 。
有两个很好的工具可以为您创建 JSON。最简单的使用是jo
:
while IFS= read -r line; do
utility "$( jo id="$( jo S="$line" )" )"
done <input.txt
另一个是jq
:
while IFS= read -r line; do
utility "$( jq -c --arg data "$line" -n '{ id: { S: $data } }' )"
done <input.txt
这两个循环都会使用您读取的数据(可能是 JSON 编码的)正确创建一个嵌套的 JSON 对象,并使用utility
该对象作为参数调用该实用程序。
使用jq
,您甚至可以将循环从内到外翻转,以避免jq
每次迭代都进行调用。执行此操作依赖于 using -c
,这使得jq
输出结果集中的每个元素都是一行(“紧凑输出”)。
jq -c -R '{ id: { S: . } }' input.txt |
while IFS= read -r json; do
utility "$json"
done
...或者让它生成你的命令和eval
它们:
eval "$(
jq -r -R '[ "utility", ({ id: { S: . } } | @json) ] | @sh' input.txt
)"
output.txt
由于您正在调用在问题中读取的文件,因此在生成该文件的某些工作流程中可能存在一些步骤。可以将utility
更早的调用集成到管道中或完全绕过它,具体取决于您正在做什么。特别是如果 ID 来自某些 JSON 文档。
答案2
只需将字符串放在双引号中,而不是单引号中。不要忘记反斜杠内部双引号。
while read line; do
command "{'\"id\"':{\"S\":\"$line\"}}"
done <output.txt
答案3
您可以在同一个 shell 字符串中混合引号,因此,如果字符串的一部分更容易使用单引号编写,而另一部分需要替换,则可以在文字部分使用单引号,在替换周围使用双引号。
$line
但请注意,如果包含双引号、反斜杠或控制字符,则生成的 JSON 格式不正确。
另请注意,plainread line
会进行一些反斜杠解释并去除空格。看理解“IFS=读取-r行”
while IFS= read -r line; do
case $line in
*[\\\"]*) echo >&2 "I'm not smart enough to handle special characters. Giving up."; exit 1;;
esac
command '{"id":{"S":"'"$line"'"}}'
done