【问题标题】:Linux - Delete all lines from a given line numberLinux - 从给定的行号中删除所有行
【发布时间】:2022-01-26 18:14:40
【问题描述】:

我正在尝试使用 sed 从提供的行号中删除文件的内容。问题是 sed 不接受我提供给它的变量

line_num=$(grep -n "debited" file.csv | sed -n '2 s/:.*//p') && sed -i.bak "$line_num,$d" file.csv

这个想法是从文件中删除 & 之后的所有行,包括模式的第二次出现。

我对@9​​87654323@ 并不固执。 Awk & perl 也可以。

【问题讨论】:

标签: linux bash perl sed


【解决方案1】:

您似乎想在第二次显示模式 (debited) 后删除文件的其余部分,包括该行。

然后可以truncate 它,以tell 为已读到该行的长度

perl -e'while (<>) { 
    if ( ($cnt += /debited/) == 2 ) { truncate $ARGV, $len; exit } 
    $len = tell;
}' file

这里$ARGV variable 有“当前”文件(从<> 读取时)。根据您的上下文,随意引入带有模式而不是文字 (debited) 的变量。

这可以在一个小脚本中看起来更好,但问题中似乎需要一个命令行程序(“one-liner”)。

【讨论】:

  • 你可以close ARGV...perl -pi.bak -e'if ( ($c += /debited/) == 2 ) { close ARGV }' file。我记得,它甚至可以处理多个文件。未经测试。
  • @TLP 是的,一个好主意——我认为它绝对应该截断它——但事实并非如此?也许我的测试有问题……
  • @TLP 哦...实际上,不能那样做:一旦第二个debited 已被读取,就太晚了,不能简单地截断我们所在的位置(即使它有效);它必须截断到该行的长度,并且无法使用close ARGV 来完成。一个好主意,不管
  • perldoc 说它可以依赖于您的系统。哦,对了,是的,您必须在支票之后打印,并使用-n
  • @usert4jju7 希望对您有所帮助 :) 感谢您的留言 :)
【解决方案2】:

我总是建议使用ed编辑文件而不是尝试使用sed 来执行此操作;从一开始就打算使用文件而不是行流的程序对于大多数任务来说效果更好。

这个想法是在 & 之后删除文件中的所有行,包括模式的第二次出现 [sic]

例子:

$ cat demo.txt
a
b
c
debited 12
d
e
debited 14
f
g
h
$ printf "%s\n" '/debited/;//,$d' w | ed -s demo.txt
$ cat demo.txt
a
b
c
debited 12
d
e

ed 命令/pattern/;//,$d 首先将当前行光标设置为与基本正则表达式pattern 匹配的第一个行光标,然后将其移动到该模式的下一个匹配项并删除其中的所有内容到文件末尾。然后w 将更改后的文件写回磁盘。

【讨论】:

  • 谢谢肖恩。选择您的解决方案而不是其他出色的解决方案,因为它可以就地编辑文件并且运行速度更快。
【解决方案3】:

你做了很多不必要的步骤,这会做你想做的。

$ awk '/debited/{c++} c==2{exit}1' file

删除第二次出现的模式及其之后的所有内容。

替换原始文件(并创建备份)

$ awk ... file > t && mv -b --suffix=.bak t file

【讨论】:

    猜你喜欢
    • 2010-12-17
    • 1970-01-01
    • 1970-01-01
    • 2018-08-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-08-11
    • 2020-11-07
    相关资源
    最近更新 更多