【问题标题】:Substitute lines in file before pattern在模式之前替换文件中的行
【发布时间】:2017-12-13 12:22:35
【问题描述】:

我有一个文件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 文件而变化,因此我无法计算每次替换的行数。

【问题讨论】:

  • $ 在正则表达式中匹配行尾,您想使用\$[$] 来匹配文字美元符号。
  • 哦,我想我现在明白了。您想删除与您的模式匹配的第一行之前的所有行,并将其替换为硬编码行。我建议你使用 sed r command(“读取文件”)。
  • @BenjaminW。没错!我已经知道我用什么来代替它们。我会看看你发布的链接,看看我能不能让它工作
  • @tripleee 感谢您指出这一点。我会修改命令

标签: regex bash sed


【解决方案1】:

如果我将您要插入的行放入单独的文件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) 出现在第一行,它会中断,但如果是这种情况,你真的可以连接你的文件。

【讨论】:

  • 这看起来你想使用sed r(就像你在评论中提到的那样)然后放弃了。与i 命令一样,r 很棘手,但请尝试使用多个-e 选项,例如sed -n -e 1r\\ -e replace.txt -e '/\$node_(2)/$p' infile(不确定r 之后的反斜杠吗?)
  • @tripleee 我曾考虑过使用r,但并不清楚是否只阅读一次,而且我认为您实际上无法使用非GNU sed 来完成,请参阅@987654323 @ - 从上面看,我看到 SLePort 提出了类似的解决方案。
【解决方案2】:

使用 GNU sed:

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

【讨论】:

  • 非常感谢!有效。 (在sed后面加了-i改文件)
【解决方案3】:

只是颠倒逻辑。

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 不同(并且功能强大得多),但唯一的区别是这是括号需要反斜杠或以其他方式转义。

【讨论】:

    【解决方案4】:

    我建议采用多步骤流程。 首先,将您想要的行放在一个文件中,例如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
    

    【讨论】:

    • 使用正则表达式查找行的行号,以便您可以在不同的命令中将其删除,这绝对是一种反模式。这是低效的,尤其是在文件很大的情况下,但无论如何,sed 可以通过正则表达式删除行就好了。
    猜你喜欢
    • 2016-06-17
    • 2023-03-12
    • 1970-01-01
    • 2019-10-02
    • 2022-08-16
    • 1970-01-01
    • 2012-04-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多