动态转义变量

baa*_*ago 3 shell-script json

我正在编写一个名称帮助脚本来自动设置"name":package.json 文件中的字段,以便它匹配某个正则表达式结构,但我在实际设置名称时遇到了一些问题。它必须匹配的正则表达式是'\@abc\/([a-z]+-{0,1})+[a-z]*$'.

现在我基本上是这样做的(还有一些额外的东西来真正断言遵循命名约定):

pattern='\@abc\/([a-z]+-{0,1})+[a-z]*$'
if [[ ! $name =~ $pattern ]]; then 
  read -rp "New name: " newName
  sed -ri "s/(\s.\"name\"\:\s\").*/\1$newName\",/g" $1/package.json
fi
Run Code Online (Sandbox Code Playgroud)

正如您可能看到的,这里的问题是变量$newName在 sed 中作为命令处理,它需要转义字符(假设用户实际上以正确的结构写入了新名称)。有没有办法做到这一点?最好尽可能不依赖。

Kus*_*nda 6

从表面上看,这个问题是How to ensure that string interpolated into `sed` replacementeses all metachars的重复。但是,sed是面向行的文本操作工具,而JSON是不面向行的结构化文档格式。因此,最好解决问题的“想要使用 JSON 文档”方面而不是“我想以sed特定方式使用”方面。


由于这与 JSON 有关,因此最好使用 JSON 感知工具,例如jq.

jq --arg newname '@abc/corrected-name' \
    'select( .name | test("^@abc/([a-z]-?)+[a-z]*$") | not ).name |= $newname' file.json
Run Code Online (Sandbox Code Playgroud)

此命令假定输入包含具有顶级name键的 JSON 文档。它(可能)修改输入文档并将结果写入标准输出。

简而言之,该jq表达式选择输入集合中具有顶级name键的所有元素,该键的值与匹配^@abc/([a-z]-?)+[a-z]*$。一旦选择了一个元素,它的name键的值就会更新为 中的值$newvalue

这样做的好处是不需要将 shell 变量注入表达式中,并且赋予内部$newname变量的值将自动进行 JSON 编码jq(如果需要以任何特定方式进行编码)。

一个输入文件,如

{
  "name": "@abc/abc-foo"
}
Run Code Online (Sandbox Code Playgroud)

此命令将保持不变,而

{
  "name": "bumblebee"
}
Run Code Online (Sandbox Code Playgroud)

会变成

{
  "name": "@abc/corrected-name"
}
Run Code Online (Sandbox Code Playgroud)