我正在编写一个名称帮助脚本来自动设置"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 中作为命令处理,它需要转义字符(假设用户实际上以正确的结构写入了新名称)。有没有办法做到这一点?最好尽可能不依赖。
从表面上看,这个问题是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)