我的文件如下所示:
FooBarA
foo bar
foo = bar
FooBarB
foo bar
foo = bar
FooBarC
foo bar
foo = bar
...
我想做的是编写一个脚本来替换 bar
中的 foo = bar
,但前提是它属于 FooBarB
。因此,在上面的示例中,仅应替换所有 bar
行中的第二个 foo = bar
。
我已经尝试过 sed
,但我就是无法正确完成。我还想避免安装任何不一定预装在系统上的工具(我使用的是 Mac OS),因为其他团队成员也会使用该脚本。
答案 0 :(得分:2)
这可能对你有用(GNU sed):
Priority 2
匹配字符串 sed '/FooBarB/{:a;n;/^$/b;/foo = bar/!ba;s//foo = baz/}' file
并开始循环。
获取下一行并研究它。
如果该行为空,则该节已完成,因此跳出循环。
如果该行不包含字符串 FooBarB
,则获取下一行并继续循环。
否则,用新值替换 foo = bar
并完成循环。
替代方案(可能适用于 macos 用户?):
bar
由于 OP 将输入数据更改为问题的另一个解决方案:
sed -e '/FooBarB/{:a' -e 'n;/^$/b;/foo = bar/!ba;s//foo = baz/;}' file
答案 1 :(得分:2)
使用 sed
(使用 macOS 的 sed 和 GNU sed 进行测试)的一种方法是:
#!/usr/bin/env sed -Ef
/FooBarB/,/^FooBar/ {
s/(foo[[:space:]]*=[[:space:]]*).+/\1new-value/
}
这是它的作用:
/FooBarB/,/^FooBar/
匹配一系列行,其中第一行匹配正则表达式 /FooBarB/
,最后一行匹配正则表达式 /^FooBar/
(这是下一个“组”)。两个正则表达式之间的逗号是 sed
中范围匹配的语法。
s/(foo[[:space:]]*=[[:space:]]*).+/\1new-value/
— [s] 替换(在匹配的行范围内)与正则表达式 (foo[[:space:]]*=[[:space:]]*).+
和 \1new-value
匹配的任何内容,其中 \1
引用第一个捕获在搜索正则表达式中分组。搜索正则表达式查找 foo
后跟可选空格,后跟一个 =
符号,再次是空格,然后是其他任何内容,在您的情况下是旧值。
您可以在一行中完成所有操作,但我想展示一个更易于理解的版本(就 sed
而言,无论如何):
sed -E '/FooBarA/,/^FooBar/s/(foo[[:space:]]*=[[:space:]]*).+/\1new-value/' temp.md
答案 2 :(得分:2)
在每个 Unix 机器上的任何 shell 中使用任何 awk:
$ awk -v tgt='FooBarB' -v val='whatever' '
NF==1{tag=$0} (NF>1) && (tag==tgt) && sub(/=.*/,"= "){$0=$0 val}
1' file
FooBarA
foo bar
foo = bar
FooBarB
foo bar
foo = whatever
FooBarC
foo bar
foo = bar
答案 3 :(得分:0)
作为参考,GNU awk 变体:
awk -v v="newvalue" 'BEGIN{FS=OFS="\n";RS=ORS="\n\n"}$1=="FooBarB"{$3="foo = " v}1' file
通过使用选项 -v
,变量 v
保存所需的字符串。
BEGIN
语句分别设置输入、输出字段分隔符,输入输出记录分隔符为一、二回车。
这样,记录由包含模式 Foobar[ABC]
的多行块组成。
最后一条语句通过重写第三行来设置新值。