在模式之前替换文件中的行

时间:2017-12-12 15:25:09

标签: regex bash sed

我有一个文件foo我想编辑。我想替换文件的所有行 在某个模式匹配之前$node_(2)

$node_(0) set X_ 46.188445620285734
$node_(0) set Y_ 400.0
# $ns_ at 0.0 "$node_(0) setdest 46.188445620285734 400.0 0.0"
$ns_ at 4.230260628522046 "$node_(0) setdest 140.0 400.0 11.073898626729083"
$ns_ at 12.70167232749509 "$node_(0) setdest 140.0 293.81155437971427 11.073898626728642"
# $ns_ at 22.290747430998636 "$node_(0) setdest 140.0 293.81155437971427 0.0"
$ns_ at 24.512130351924498 "$node_(0) setdest 140.0 121.22627768528247 11.143254728766196"
$node_(1) set X_ 284.3754249089888
$node_(1) set Y_ 400.0
$ns_ at 0.0 "$node_(1) setdest 358.5058741786957 400.0 10.938908248230844"
# $ns_ at 6.776768539190925 "$node_(1) setdest 358.5058741786957 400.0 0.0"
$ns_ at 8.52331532068547 "$node_(1) setdest 400.0 400.0 11.27995015881709"
$ns_ at 12.201888828288247 "$node_(1) setdest 400.0 341.4941258213043 11.279950158817115"
# $ns_ at 17.388602719303435 "$node_(1) setdest 400.0 341.4941258213043 0.0"
$ns_ at 22.22922653365822 "$node_(1) setdest 400.0 141.4941258213043 11.258336966410015"
$node_(2) set X_ 270.0 //so basically here is the pattern match
$node_(2) set Y_ 293.0222761518543
.
.
.

该文件应该如下所示

$node_(0) set X_ 10.0
$node_(0) set Y_ 10.0
$node_(1) set X_ 510.0
$node_(1) set Y_ 510.0
$node_(2) set X_ 270.0 //pattern and everything after it is left intact
$node_(2) set Y_ 293.0222761518543
.
.
.

我尝试了用sed

sed -i -e '/$node_(0)/,/$node_(2)/c\$node_(0)\ set X_ 10.0 \n$node_(0) set Y_ 10.0\n$node_(1) set X_ 510.0\n$node_(1) set Y_ 510.0' foo

但它会完全删除第一个$node_(2)行。此外,$node_(2)之前的行数会针对每个新foo文件进行更改,因此我无法计算每次替换的行数。

4 个答案:

答案 0 :(得分:2)

只需颠倒逻辑。

sed -n '1i \
$node_(0) set X_ 10.0\
$node_(0) set Y_ 10.0\
$node_(1) set X_ 510.0\
$node_(1) set Y_ 510.0
    /[$]node_(2)/,$p' file

1是一个地址表达式,用于选择第一行,i是一个插入文本的命令。唉,i命令没有完全标准化,因此实现细节和语法(特别是插入多行)在不同平台之间有所不同。为了易读性和可移植性,可以切换到Perl:

perl -i -ne 'BEGIN { print <<__the_end_of_the_BEGIN__; }
\$node_(0) set X_ 10.0
\$node_(0) set Y_ 10.0
\$node_(1) set X_ 510.0
\$node_(1) set Y_ 510.0
__the_end_of_the_BEGIN__
    $p=1 if /^\$node_\(2\)/;
    print if $p;' file

您可以编写一个非常相似的Awk脚本,但不能移植支持sed -i / perl -i等文件的就地编辑。

Perl使用美元符号作为标量变量的标志,因此必须将它们转义为字面打印,正则表达方言与传统sed或Awk不同(并且功能更强大),但是唯一不同的是,括号需要被反斜或以其他方式逃脱。

答案 1 :(得分:2)

如果我将要插入的行放入单独的文件replace

$node_(0) set X_ 10.0
$node_(0) set Y_ 10.0
$node_(1) set X_ 510.0
$node_(1) set Y_ 510.0

我可以这样做:

$ sed -n '/\$node_(2)/,$p' infile | cat replace -
$node_(0) set X_ 10.0
$node_(0) set Y_ 10.0
$node_(1) set X_ 510.0
$node_(1) set Y_ 510.0
$node_(2) set X_ 270.0 //so basically here is the pattern match
$node_(2) set Y_ 293.0222761518543

sed命令默认禁止打印(-n),然后打印\$node_(2)的第一个匹配项中的所有行(逃避$这里不是绝对必要的,但总是一个好主意,如果您不要将它用作行尾锚点)到文件的末尾($地址)。

cat命令首先打印替换文件,然后输出sed命令的输出。

或使用sed r ("read") command (提示tripleee建议使用-e

$ sed -n -e '1r replace' -e '/\$node_(2)/,$p' infile
$node_(0) set X_ 10.0
$node_(0) set Y_ 10.0
$node_(1) set X_ 510.0
$node_(1) set Y_ 510.0
$node_(2) set X_ 270.0 //so basically here is the pattern match
$node_(2) set Y_ 293.0222761518543

这些命令被分成多个-e块,因为r对于它所看到的文件名有点挑剔。如果$node_(2)出现在第一行,它就会中断,但如果是这种情况,你可以真正地连接你的文件。

答案 2 :(得分:1)

使用GNU sed:

sed '0,/$node_(2)/{//!d;s//text to add\n&/}' file

答案 3 :(得分:-1)

我建议采用多步骤流程。 首先,将您想要的行放在文件中,例如header.txt

现在,找到要删除的最后一行的行号:

$ first=$( grep -n '^\$node_(2)' test.txt | head -1 | cut -d: -f1 )
$ last=$(( first -1 ))

从文件中删除这些行:

$ sed "1,${first}d" myfile.txt

现在,将这两个文件放入临时文件并重命名临时文件:

$ cat header.txt myfile.txt > tmp$$  &&  mv tmp$$ myfile.txt