关于unix:使用sed从文本文件中删除特定的行号?

Delete specific line number(s) from a text file using sed?

我想从文件中删除一个或多个特定的行号。 我怎么用sed这样做?


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

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

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

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

这会将文件备份到file.bak,并删除给定的行。

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


您可以删除特定的单行及其行号
sed -i'33d'文件

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


和awk一样

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


1
2
3
4
5
6
7
8
9
10
11
$ cat foo
1
2
3
4
5
$ sed -e '2d;4d' foo
1
3
5
$

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

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

(其中deletelines是您想象中所需的实用程序)与之相同

1
grep -v error logfile

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

1
sed 's%$%d%' linenumbers

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

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

在某些平台上,sed -f不理解选项参数-表示标准输入,因此您必须将脚本重定向到临时文件,并在完成后将其清理,或者用<替换单独的短划线x15>或/proc/$pid/fd/1如果您的操作系统(或shell)具有此功能。

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


我想用awk提出一个概括。

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

1
2
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中写入当前块内的行号。 (见下文)
  • ||&&是逻辑运算符OR和AND。
  • print $0写完整行
1
2
3
4
5
6
7
8
9
10
11
12
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      |
+-----+------+----------+------------+