在 shell 脚本参数中以开发人员友好的方式编写 JSON

Write JSON in developer-friendly fashion in shell script arguments

提问人:Cyril Duchon-Doris 提问时间:4/27/2023 最后编辑:Cyril Duchon-Doris 更新时间:4/27/2023 访问量:30

问:

我有一个shellscript,我需要将JSON作为函数参数传递

我想编写对开发人员友好的缩进代码,而不是编写难以维护的单行参数,或带有转义换行符和引号的多行参数

我从什么开始

kubectl patch deployment ${APP_NAME} \
      --patch="{\"spec\":{\"template\":{\"metadata\":{\"annotations\":{\"friendly_tag\":\"${FRIENDLY_TAG}\",\"deployed_by\":\"${DEPLOYED_BY}\"}}}}}" \

我想以什么结束(下面的例子显然在 shell 中不起作用)

kubectl patch deployment ${APP_NAME} \
      --patch={ 
         "spec": {
              "template": {
                  "metadata": {
                      "annotations": {
                          "friendly_tag": "${FRIENDLY_TAG}",
                          "deployed_by": "${DEPLOYED_BY}"
                      }
                  }
              }
          }

有没有办法在不使用其他变量的情况下保留这样的语法?否则,我该如何在保持开发人员友好性的同时编写我的 shellscript?

我知道我可以使用heredocs,但是如果我有2个JSON参数要传递给我的函数,我不确定是否可以使用它们(除了将我的heredoc放在变量中并将它们作为参数传递)

此外,在这种情况下,json 引号需要转义,所以我不确定 heredocs 是否方便。

编辑:我正在谈论的heredoc语法(强制你有一个未缩进的结束标签)JSON

PATCH=$(jq -R -s --raw-output '.' <<-JSON
        {
          "spec": {
            "template": {
              "metadata": {
                "annotations": {
                  "friendly_tag": "${FRIENDLY_TAG}",
                  "deployed_by": "${DEPLOYED_BY}"
                }
              }
            }
          }
        }
JSON
    )
    kubectl patch deployment ${APP_NAME} \
      --patch="${PATCH}" \
      --context ${KUBECTL_CONTEXT} \
      -n ${ENVIRONMENT}
shell pretty-print heredoc

评论

0赞 Charles Duffy 4/27/2023
heredoc 方法也是不安全的;它不会转义您的数据以使其成为有效的 JSON(如果尚未生效)。总的来说,我建议你在编写 shell 时更多地担心正确性和安全性,而不是对开发人员的友好性。
0赞 Charles Duffy 4/27/2023
(如果你通过 shellcheck.net 运行你的代码,你会看到其他的错误,比如不能保证扩展到一个单词;这是另一种情况,因为 1970 年代做出的错误设计决策,shell 本质上是对人类不友好的,并且有必要注入一定数量的仪式——比如引用或——以确保你的代码在运行时不会做错误的事情)。${APP_NAME}"${APP_NAME}""$APP_NAME"
0赞 Charles Duffy 4/27/2023
...一般来说,如果你的首要任务是让代码看起来很漂亮,我强烈建议你选择一种不同的语言;理想情况下,带有宏的东西,这样你就可以编写代码,将人们编写的代码压缩成你需要的形式。如果你要编写要从 shell 使用的工具,让这些工具的用户需要知道他们在做什么以避免安全性和正确性错误是完全不可避免的。(如果提出权威上诉的论点有帮助,我可以尝试这样做)。

答:

2赞 Charles Duffy 4/27/2023 #1

在你进入友好状态之前,对正确性有更大的担忧。要解决这些问题,请考虑:

export FRIENDLY_TAG DEPLOYED_BY # variables need to be in the environment

kubectl patch deployment "${APP_NAME}" \
  --patch="$(jq -n '
    { 
      "spec": {
        "template": {
          "metadata": {
            "annotations": {
              "friendly_tag": env.FRIENDLY_TAG,
              "deployed_by": env.DEPLOYED_BY
            }
          }
        }
      }
    }')"

在不影响正确性的情况下,这是尽可能友好的。

  • 在 jq 表达式周围使用单引号可确保该表达式中不需要任何额外的反斜杠。
  • 使用 jq 引用来引用环境变量可以避免使用 to 将参数传递到 jq 的仪式。env--arg
  • 带有文字引号、制表符、换行符、反斜杠或其他 jq 语法的标记(或deployed_by值)将被正确转义,而不是能够将任意 JSON 内容注入输出文档(或者,如果发生错误而不是恶意活动,而不是使该输出不再有效 JSON)。

评论

0赞 Cyril Duchon-Doris 4/27/2023
感谢您的完整答案和警告!非常感谢。
0赞 Ivan 4/27/2023
如果由于拼写错误或拼写错误而返回错误怎么办?猜猜先创建 var 并检查它是否正确,然后再做补丁更安全。jq
0赞 Cyril Duchon-Doris 4/27/2023
您能解释一下如何使用 curl 数据二进制吗?在我之前的脚本中,我使用了 .我不确定我是否可以在那里以同样的方式使用 jq......(对不起,如果它跑题了)curl -X POST -H 'Content-type: application/json' \ --data-binary @- << JSON ${SLACK_WEBHOOK} {...} JSON
0赞 Charles Duffy 4/27/2023
@Ivan、拼写错误或错别字在哪里?在代码中?这就是测试的目的。它不会关心数据的问题;在环境变量中有效的任何数据都可以转换为 JSON 字符串,也可以将某些无效的值转换为 JSON(NUL 在环境变量中是不可能的,但可以在 JSON 字符串中转换为 NUAL)。\u0000
1赞 Charles Duffy 4/27/2023
@CyrilDuchon-Doris,假设你有一个带有 ksh93 扩展的 shell(也存在于 bash 和 zsh 中),;而如果您仅保证 POSIX 合规性,.也可以使用 ,然后是包含 JQ 表达式的行,然后是 ,然后是 (根据需要替换 sigil)。--data-binary @- < <(jq -n '...')jq -n '...' | curl ... --data-binary @---data-binary @- <<EOF$(jq -n '')EOF