我试图找到两个连续行的模式,其中第一行是固定字符串,第二行有我喜欢替换的部分子字符串。
这是在macOS的sh
或bash
中完成的。
如果我手头有一个可以对整个文本进行操作的正则表达式工具,这对我来说会很容易。然而,我所发现的只是bash的简单文本替换-它不能与regex和sed
一起工作,这是面向行的。
我怀疑我可以以一种方式使用sed
,它首先找到匹配的第一行,只有在它的模式也匹配的情况下才会替换下面的行,但我无法弄清楚。
或者macOS上是否有其他工具可以让我对整个文件或字符串进行基于正则表达式的搜索和替换?也许使用Python(安装了v2.7和v3)?
下面是一个示例文本,以及我对它的修改方式:
keyA
value:474
keyB
value:474 <-- only this shall be replaced (follows "keyB")
keyC
value:474
keyB
value:474
现在,我想找到所有第一行为"keyB"下面一行是"value:474",然后用另一个值替换第二行,例如"value:888"
作为一个忽略行分隔符的正则表达式,我会这样写:
- Search:
(bkeyBns*value):474
- 替换:
$1:888
所以,基本上,我找到了474之前的模式,然后用相同的模式加上新的数字888替换它,从而保留了原来的缩进(这是可变的)。
可以使用
sed -e '/keyB$/{n' -e 's/(.*):[0-9]*/1:888/' -e '}' file
# Or, to replace the contents of the file inline in FreeBSD sed:
sed -i '' -e '/keyB$/{n' -e 's/(.*):[0-9]*/1:888/' -e '}' file
细节:
/keyB$/
-查找所有以keyB
结尾的行n
-清空当前模式空间并读入下一行s/(.*):[0-9]*/1:888/
-找到任何文本直到最后一个:
+零或更多的数字捕获文本到组1,并替换为组和:888
的内容。
{...}
创建一个block,该block只在满足/keyB$/
条件时执行。
查看sed
在线演示
使用带有-0777
的perl一行代码扫描多行:
$ # inline edit:
$ perl -0777 -i -pe 's/bkeyBs*value):d*/$1:888/' file.txt
$ # to stdout:
$ cat file.txt | perl -0777 -pe 's/bkeyBs*value):d*/$1:888/'
bash:
#!/bin/bash
keypattern='^[[:blank:]]*keyB$'
valpattern='(.*):'
replacement=888
while read -r; do
printf '%sn' "$REPLY"
if [[ $REPLY =~ $keypattern ]]; then
read -r
if [[ $REPLY =~ $valpattern ]]; then
printf '%s%sn' "${BASH_REMATCH[0]}" "$replacement"
else
printf '%sn' "$REPLY"
fi
fi
done < file