如何在单引号中使用参数

如何在单引号中使用参数

我有一个文件,其中包含 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

相关内容