【问题标题】:Delete specific line number(s) from a text file using sed?使用 sed 从文本文件中删除特定的行号?
【发布时间】:2011-01-07 22:06:40
【问题描述】:

我想从文件中删除一个或多个特定的行号。我将如何使用 sed 做到这一点?

【问题讨论】:

  • 你能举一个更具体的例子来说明你想要什么吗?您将如何决定删除哪些行?
  • 也许另见*.com/questions/13272717/… 并反向应用(如果键不在关联数组中则打印)。

标签: unix sed line-numbers


【解决方案1】:

如果要删除第 5 到 10 行和第 12 行:

sed -e '5,10d;12d' file

这会将结果打印到屏幕上。如果要将结果保存到同一个文件中:

sed -i.bak -e '5,10d;12d' file

这会将未修改的文件存储为file.bak,并删除给定的行。

注意:行号从 1 开始。文件的第一行是 1,而不是 0。

【讨论】:

  • 并非所有的 unix 都使用“-i”进行 gnu sed。不要犯回退到“sed cmd 文件 > 文件”的错误,这会清除你的文件。
  • 如果我想删除第 5 行直到最后一行怎么办?
  • @WearetheWorld sed -e '5,$d' file
  • @KanagaveluSugumar sed -e '5d' file。语法为<address><command>;其中<address> 可以是像5 这样的单行或像5,10 这样的一系列行,命令d 删除给定的一行或多行。地址也可以是正则表达式,或表示文件最后一行的美元符号$
  • 注意第5行到第10行都包含在内。
【解决方案2】:

您可以删除特定的单行及其行号

sed -i '33d' file

这将删除第 33 行号上的行并保存更新的文件。

【讨论】:

  • 在我的例子中,“sed”删除了一个错误的行。所以我使用这种方法:sed -i '0,/<TARGET>/{/<NEW_VALUE>/d;}' '<SOME_FILE_NAME>'。谢谢!
  • 同样,我写了一个循环,奇怪的是有些文件丢失了正确的行,但有些文件也丢失了另一行,不知道出了什么问题。 (GNU/Linux bash4.2) 下面的 awk 命令在循环中运行良好
  • 如果要从行列表中删除,请务必小心使用 sort -r,否则您的第一个 sed 会更改其他所有内容的行号!...
  • 关于在循环中删除错误行的问题:一定要从最大的行号开始,否则每个删除的行都会偏移行号......
  • 在我的系统上,当处理大文件时,sed 看起来比 headtail 的简单组合慢一个数量级:这是一个更快的方法示例(没有 in-放置模式):delete-line() { local filename="$1"; local lineNum="$2"; head -n $((lineNum-1)) "$filename"; tail +$((lineNum+1)) "$filename"; }
【解决方案3】:

还有 awk

awk 'NR!~/^(5|10|25)$/' file

【讨论】:

  • 注意:awk 行对我来说比 sed 变体更可靠(在 OS-X 和 Ubuntu Linux 之间)
  • 请注意,这不会删除文件中的任何内容。它只是将没有这些行的文件打印到标准输出。所以你还需要将输出重定向到一个临时文件,然后移动临时文件替换原来的。
【解决方案4】:
$ cat foo
1
2
3
4
5
$ sed -e '2d;4d' foo
1
3
5
$ 

【讨论】:

    【解决方案5】:

    这通常是反模式的症状。产生行号的工具很可能被替换为立即删除行的工具。例如;

    grep -nh error logfile | cut -d: -f1 | deletelines logfile
    

    (其中deletelines 是您想象中需要的实用程序)与

    相同
    grep -v error logfile
    

    话虽如此,如果您确实需要执行此任务,您可以从行号文件生成一个简单的sed 脚本。幽默地(但可能有点令人困惑)您可以使用 sed 来做到这一点。

    sed 's%$%d%' linenumbers
    

    这接受一个行号文件,每行一个,并在标准输出中生成相同的行号,每个行号后面附加d。这是一个有效的 sed 脚本,我们可以将其保存到文件中,或者(在某些平台上)通过管道传输到另一个 sed 实例:

    sed 's%$%d%' linenumbers | sed -f - logfile
    

    在某些平台上,sed -f 不理解选项参数- 表示标准输入,因此您必须将脚本重定向到一个临时文件,并在完成后清理它,或者替换单独的如果您的操作系统(或外壳)有,请使用 /dev/stdin/proc/$pid/fd/1 破折号。

    与往常一样,您可以在-f 选项之前添加-i 以使sed 编辑目标文件,而不是在标准输出中生成结果。在 *BSDish 平台(包括 OSX)上,您还需要为 -i 提供显式参数;一个常见的习惯用法是提供一个空参数; -i ''.

    【讨论】:

    • 我不太同意“反模式的症状”。基于标记的文件类型(例如 XML 或 JSON)在末尾需要特定的行才能成为有效文件。在这种情况下,删除这些行,将要添加的内容放入文件中,然后重新添加这些行,通常是最合理的方法,因为直接将这些行放在中间可能会更加努力,并且违背尽可能避免使用 sed 等额外工具的潜在愿望。
    • 我不太明白你在想象什么样的场景。 场景中这是一种合法的方法,但我所见过的绝大多数情况都是新手,他们或多或少地与我的第一个示例所展示的完全一致。 (也许它们来自一些非常低级的语言,并且习惯于将问题划分到分子级别之外,因为您必须在 asm 或 C 中。)
    • 按行号从 XML 或 JSON 中删除内容听起来非常很脆弱,如果不是完全危险的话。
    • 我的基本意思是,作为这样一个文件的创建者,您知道文档末尾必须是什么(即最后的一组右大括号/方括号JSON 的几行,或 XML 的确切结束标记)。意识到这一点,扩展此类文档的最简单方法是 1)删除最后几行,2)添加新内容,3)重新添加最后几行。这样,文档在扩展之前和之后都可以有效,而无需找到在文档中间添加行的方法。
    • 到目前为止,这是针对大量行(即由文件提供)提供适当解决方案的唯一答案。前言也很有意义。它值得更多的支持。顺便说一句,如果您想打印行而不是删除它们,请使用p 而不是d,以及选项-n(如果没有-n 和@987654344,它将无法工作@ 也不起作用)。
    【解决方案6】:

    我想用 awk 提出一个概括。

    当文件由固定大小的块组成时 并且对于每个块重复要删除的行, awk 可以通过这种方式正常工作

    awk '{nl=((NR-1)%2000)+1; if ( (nl<714) || ((nl>1025)&&(nl<1029)) ) print  $0}'
     OriginFile.dat > MyOutputCuttedFile.dat
    

    在此示例中,块的大小为 2000,我想打印 [1..713] 和 [1026..1029] 行。

    • NR 是 awk 用来存储当前行号的变量。
    • % 给出两个整数相除的余数(或模数);
    • nl=((NR-1)%BLOCKSIZE)+1 这里我们在变量 nl 中写入当前块内的行号。 (见下文)
    • ||&amp;&amp; 是逻辑运算符 ORAND
    • print $0 写了整行

    Why ((NR-1)%BLOCKSIZE)+1:
    (NR-1) We need a shift of one because 1%3=1, 2%3=2, but 3%3=0.
      +1   We add again 1 because we want to restore the desired order.
    
    +-----+------+----------+------------+
    | NR  | NR%3 | (NR-1)%3 | (NR-1)%3+1 |
    +-----+------+----------+------------+
    |  1  |  1   |    0     |     1      |
    |  2  |  2   |    1     |     2      |
    |  3  |  0   |    2     |     3      |
    |  4  |  1   |    0     |     1      |
    +-----+------+----------+------------+
    

    【讨论】:

    • 我很欣赏你不辜负你的疯狂名字的方式。
    【解决方案7】:

    最短,删除sed中的第一行

    sed -i '1d' file

    正如 Brian 所说的 here&lt;address&gt;&lt;command&gt; 被使用,&lt;address&gt;&lt;1&gt;&lt;command&gt; &lt;d&gt;

    【讨论】:

      最近更新 更多