用多行引用字符串替换 sed 参数

PHD*_*PHD 5 sed json

目标

将文本替换"scripts: {"为以下字符串

"scripts": {
    "watch": "tsc -w",
Run Code Online (Sandbox Code Playgroud)

在一个json文件中。

尝试

我为源字符串和目标字符串创建了两个变量:

第一次尝试

SRC='"scripts": {'
DST='"scripts": {
    "watch": "tsc -w",'
Run Code Online (Sandbox Code Playgroud)

并运行以下命令:

sed "s/$SRC/$DST/" foo.json
Run Code Online (Sandbox Code Playgroud)

这已经失败了。

第二次尝试

这次我转义了源字符串和目标字符串的双引号:

SRC="\"scripts\": {"
DST="\"scripts\": {
    \"watch\": \"tsc -w\",
    \"dev\": \"nodemon dist/index.js\","
Run Code Online (Sandbox Code Playgroud)

并运行与上面相同的命令,但失败了。

第三次和第四次尝试

我使用以下命令尝试了如上定义的变量:

sed 's/'"$SRC"'/'"$DST"'/' foo.json
Run Code Online (Sandbox Code Playgroud)

这已经失败了。

所有这些尝试都产生了错误

unterminated 's' command
Run Code Online (Sandbox Code Playgroud)

出了什么问题?

Kus*_*nda 8

假设您的 JSON 文档看起来像

{
  "scripts": {
    "other-key": "some value"
  }
}
Run Code Online (Sandbox Code Playgroud)

...并且您想在.scripts对象中插入一些其他键值对。然后你可以jq用来做这个:

$ jq '.scripts.watch |= "tsc -w"' file.json
{
  "scripts": {
    "other-key": "some value",
    "watch": "tsc -w"
  }
}
Run Code Online (Sandbox Code Playgroud)

或者,

$ jq '.scripts += { watch: "tsc -w" }' file.json
{
  "scripts": {
    "other-key": "some value",
    "watch": "tsc -w"
  }
}
Run Code Online (Sandbox Code Playgroud)

这两个都将替换已经存在的.scripts.watch条目。

请注意,其中键值对的顺序.scripts并不重要(因为它不是数组)。

如果要保存,请将输出重定向到新文件。

将多个键值对添加到同一个对象:

$ jq '.scripts += { watch: "tsc -w", dev: "nodemon dist/index.js" }' file.json
{
  "scripts": {
    "other-key": "some value",
    "watch": "tsc -w",
    "dev": "nodemon dist/index.js"
  }
}
Run Code Online (Sandbox Code Playgroud)

结合jo创建需要添加到.scripts对象的JSON :

$ jq --argjson new "$( jo watch='tsc -w' dev='nodemon dist/index.js' )" '.scripts += $new' file.json
{
  "scripts": {
    "other-key": "some value",
    "watch": "tsc -w",
    "dev": "nodemon dist/index.js"
  }
}
Run Code Online (Sandbox Code Playgroud)

sed适合解析面向行的文本。JSON 没有以换行符分隔的记录,sed也不知道 JSON 的引用和字符编码规则等。要正确解析和修改这样的结构化数据集(或 XML、YAML,在某些情况下甚至是 CSV),您应该使用适当的解析器。

作为jq在这种情况下使用的额外好处,您可以获得一些易于修改以满足您的需要的代码,并且同样易于修改以支持输入数据结构的更改。


ter*_*don 6

Kusalananda说专用解析器是完成这项工作的正确工具是绝对正确的。然而,这也可以很容易地在sed(至少在sed理解GNU 的情况下\n)中完成。通过尝试替换整个两行模式,您使事情变得更加复杂。相反,只需匹配目标字符串并在其后插入替换:

"scripts": {
Run Code Online (Sandbox Code Playgroud)

进而:

$ sed '/"scripts": {/s/$/\n    "watch": "tsc -w",/' file
"scripts": {
    "watch": "tsc -w",
Run Code Online (Sandbox Code Playgroud)

这意味着“如果此行与 string 匹配"scripts": {,则将行尾替换为换行符 ( \n) 后跟 "watch": "tsc -w",。或者,您可以使用ased 命令附加文本:

$ sed '/"scripts": {/a\    "watch": "tsc -w",' file 
"scripts": {
    "watch": "tsc -w",
Run Code Online (Sandbox Code Playgroud)