我有一个网表文件。它有分割线。分割符号是位于续行开头的“+”。
MP1 Y A VDD VDD pch_25 W=1u L=550n M=1
MP0 Y B
+VDD VDD pch_25 W=1u L=550n M=1
MN1 v0 A VSS VSS nch_25_dnw W=500.0n L=550n M=1
MN0 Y B v0 VSS nch_25_dnw W=500.0n L=550n M=1
如果该(完整)行包含“pch_25”,我想用“X”替换每行的开头“M”,因此所需的输出是
XP1 Y A VDD VDD pch_25 W=1u L=550n M=1
XP0 Y B
+VDD VDD pch_25 W=1u L=550n M=1
MN1 v0 A VSS VSS nch_25_dnw W=500.0n L=550n M=1
MN0 Y B v0 VSS nch_25_dnw W=500.0n L=550n M=1
我有以下(工作)命令:
sed -e :a -e '$!N;s/\n+/\\/;ta' -e 'P;D' file \
| sed '/pch_25/s/^M/X/' | sed -e 's/\\/\n+/g'
如何用一个sed
没有管道的命令替换这个命令?
答案1
N;P;D
通常,您会使用 in模式执行类似的任务sed
,以始终将缓冲区中的两行保持在一起。不幸的是,网表文件可以将一条记录拆分为多行,因此通常的解决方案将不起作用。
显而易见的解决方案是添加一个循环来收集属于在一起的所有行:
sed -e :a -e '/pch_25/s/^M/X/;/\n[^+]/!{N;ba' -e '};P;D' file
/pch_25/s/^M/X/
是我们要执行的实际替换:在包含 的行中pch_25
,s
将前导(^
锚点)替换M
为X
。- 该模式
\n[^+]
定义了一个换行符,后跟一些除 之外的其他字符+
,这表明我们添加了太多行并且必须退出循环。换句话说,如果我们用 反转匹配!
,我们可以附加下一行N
并ba
跳转到循环标记:a
- 最后,通常
P;D
打印并删除缓冲区的第一行,并开始一个新的循环。是的,如果我们已经在缓冲区中收集了两行以上,则只有第一行会被打印和删除。但没问题:下一个周期不会替换任何内容,因为模式将以+
, not开头M
,其他行将被相继删除
先进的解决方案:
现在我有一个想法,将N;P;D
模式扩展为多行,没有跳转标记和b
.这个想法是D
通过在模式的开头添加换行符来使用for 循环,换行符可以通过以下方式删除D
(注意:这是 GNUsed
代码):
sed '/pch_25/s/^M/X/;/\n[^+]/!N;//P;//!s/^/\n/;D' file
/\n[^+]/!N
如果我们仍然在同一个网络记录中,则添加换行符//
重复最后一个模式,这里没有反转,所以如果我们添加太多一行,我们可以P
打印第一部分//!s/^/\n/
如果我们仍在一条记录中,则在模式的开头添加一个换行符,所以最后的D
如果我们必须检查替换,则将在重新开始之前仅删除添加的空行,或者如果我们已经在下一条记录中,则删除已打印的第一行
不幸的是,替换中使用的\n
是 GNU 的非标准添加sed
,因此您不能依赖它,而必须找到另一种方法来添加换行符,例如附加到保留空间、清空模式空间和x
更改空间:
sed '/pch_25/s/^M/X/;/\n[^+]/!N;//P;//!{H;s/.*//;x;};D' file