如何使用sed删除文件的最后n行


148

我想从文件末尾删除一些n行。可以使用sed完成此操作吗?

例如,要删除2到4行,我可以使用

$ sed '2,4d' file

但是我不知道行号。我可以使用删除最后一行

$sed $d file

但我想知道从末尾删除n行的方法。请让我知道如何使用sed或其他方法进行操作。


2
@arashkordi:它从文件的顶部而不是底部使用行数。
2012年

有关超级用户的相关问题。
雷神

//,或许考虑改写的问题,使其比更普遍的公正 sed
内森·巴桑尼斯

1
sed $d file返回错误。相反,$ d应该在引号内,如下所示:sed '$d' file
Akronix

Answers:


221

我不知道sed,但是可以用head

head -n -2 myfile.txt

19
为简单起见,+ 1。等效sed命令对接难看:sed -e :a -e '$d;N;2,5ba' -e 'P;D' file,5对于最后5行)。
Marc B

62
请注意,这适用于的某些版本head,但不是标准版本。实际上,head州的标准:The application shall ensure that the number option-argument is a positive decimal integer.
威廉·珀塞尔

21
要添加到@WilliamPursell的答案中,请执行以下操作:在Mac OS默认外壳程序上,此方法无效。
JDS 2015年

7
在BSD上也没有,但是问题被标记为Linux。
2015年

3
减1,因为除了osx之外,这在Ubuntu14上也不适合我head: illegal line count -- -2
Michael Durrant

30

如果硬编码n是一个选项,则可以使用顺序调用来sed。例如,要删除最后三行,请删除最后三行:

sed '$d' file | sed '$d' | sed '$d'

2
这加上-i在适当位置编辑文件,而不是将其转储到stdout,对我来说很有效。
WAF 2015年

27

sed的俏皮话

# delete the last 10 lines of a file
sed -e :a -e '$d;N;2,10ba' -e 'P;D'   # method 1
sed -n -e :a -e '1,10!{P;N;D;};N;ba'  # method 2

似乎是您要寻找的东西。


@Thor你可以通过改变改变多少行从文件中删除10'$d;N;2,10ba'
Alexej马古拉

1
@AlexejMagura:我在评论早期版本。
雷神

22

一个有趣而简单的sedtac解决方案:

n=4
tac file.txt | sed "1,$n{d}" | tac

注意

  • "shell需要双引号来评估命令中的$n变量sed。用单引号将不会执行插值。
  • taccat颠倒的,看man 1 tac
  • {}sed是否有分离$nd(如果不是,壳尝试插值不存在的$nd变量)

7
tacosx上的fyi no
Michael Durrant 2015年

1
@MichaelDurrant port info coreutils|| brew info coreutils;
声音

19

使用sed,但让Shell进行数学运算,目标是d通过给出一个范围来使用命令(删除最后23行):

sed -i "$(($(wc -l < file)-22)),\$d" file

要从内到外删除最后3行:

$(wc -l < file)

给出文件的行数:说2196

我们要删除最后23行,因此对于左侧或范围:

$((2196-22))

给出:2174 因此,shell解释后的原始sed是:

sed -i '2174,$d' file

通过-i执行就地编辑,文件现在为2173行!

如果要将其保存到新文件中,代码为:

sed -i '2174,$d' file > outputfile

15

您可以为此使用head

$ head --lines=-N file > new_file

其中N是要从文件中删除的行数。

现在,原始文件的内容减去最后N行在new_file中


8

为了完整起见,我想添加我的解决方案。我最终用标准的方法这样做ed

ed -s sometextfile <<< $'-2,$d\nwq'

这将使用就地编辑删除最后两行(尽管它确实使用了/tmp!!中的临时文件)


5

要真正截断非常大的文件,我们有truncate命令。它不知道行,但是tail+ wc可以将行转换为字节:

file=bigone.log
lines=3
truncate -s -$(tail -$lines $file | wc -c) $file

如果同时写入文件,则存在明显的竞争条件。在这种情况下,最好使用head-它从文件开头(注意磁盘IO)开始计数字节,因此我们将始终在行边界处截断(如果主动写入文件,则可能比预期的行数多):

truncate -s $(head -n -$lines $file | wc -c) $file

如果您登录失败,则方便一线尝试将密码代替用户名:

truncate -s $(head -n -5 /var/log/secure | wc -c) /var/log/secure

4

这可能对您有用(GNU sed):

sed ':a;$!N;1,4ba;P;$d;D' file

真好 您错过了结尾的撇号(')。
雷神

很抱歉这么晚发表评论,但是我尝试((适用于我的AIX / posix)它除了最后一行以外都无法打印。读代码,我不明白最后四行是如何去除,明确循环是在第4行等以后它肯定环路dD或者P用GNU sed的,而不是在POSIX版本。似乎没有D在行之后打印行,并保留在工作缓冲区中以进行新循环,而不传递到动作行的“结束”行。
NeronLeVelu

@NeronLeVelu程序在4行的窗口中读取到模式空间,然后追加下一行并打印第一行,直到到达文件末尾,然后删除其余行。
potong

@potong是的,我在GNU sed上进行了测试,它在posix D产生相反效果后将行之间的缓冲区保持在posix卸载的位置。
NeronLeVelu

4

上面的大多数答案似乎都需要GNU命令/扩展名:

    $ head -n -2 myfile.txt
    -2: Badly formed number

对于更便携的解决方案:

     perl -ne 'push(@fifo,$_);print shift(@fifo) if @fifo > 10;'

要么

     perl -ne 'push(@buf,$_);END{print @buf[0 ... $#buf-10]}'

要么

     awk '{buf[NR-1]=$0;}END{ for ( i=0; i < (NR-10); i++){ print buf[i];} }'

其中“ 10”是“ n”。


2

有了这里的答案,您已经了解到sed不是此应用程序的最佳工具。

但是我确实认为使用sed可以做到这一点。这个想法是添加N行以保持空间,直到您可以阅读而不会触及EOF。当击中EOF时,打印保留空间的内容并退出。

sed -e '$!{N;N;N;N;N;N;H;}' -e x

上面的sed命令将省略最后5行。


2

尝试以下命令:

n = line number
tail -r file_name | sed '1,nd' | tail -r

请解释这是如何工作的。仅供参考-初始化shell变量时,我们不应在周围有空格=
codeforester

@codeforester我想第一行是一条评论。他只使用tail -r其他人用来tac反转行顺序的位置,并使最后n一行成为n第一行。
Nicolas Melay

2

它可以通过3个步骤完成:

a)计算要编辑的文件中的行数:

 n=`cat myfile |wc -l`

b)从该数字中减去要删除的行数:

 x=$((n-3))

c)告诉sed从该行号($x)到结尾删除:

 sed "$x,\$d" myfile

数学不好。如果必须删除3线,然后减去3但增加1.你的数学,如果该文件有10行,10 - 3 = 7,您使用sed删除线7至10,即4线,没有3
mathguy18年

1

您可以获取wc -l <file>和使用的总行数

head -n <total lines - lines to remove> <file>


1

这将从以下内容中删除最后3行file

for i in $(seq 1 3); do sed -i '$d' file; done;


1
这对于大文件来说太昂贵了-整个文件必须被读取和重写n次!和尽可能多的叉子sed
codeforester

尽管这可能不是最有效的解决方案,但它却是最直接,最容易理解的方法
Dharam

0

我更喜欢这种解决方案;

head -$(gcalctool -s $(cat file | wc -l)-N) file

其中N是要删除的行数。



0

要删除最后4行:

$ nl -b a file | sort -k1,1nr | sed '1, 4 d' | sort -k1,1n | sed 's/^ *[0-9]*\t//'   

与头部相比要重一些(尤其是在资源上)。至少tac file | sed '1,4d' | tac因为排序然后删除前缀会花费大量资源。
NeronLeVelu 2015年

@NeronLeVelu你是对的,但是tac某些系统没有命令(例如FreeBSD?)
mstafreshi

0

我想出了这个,其中n是要删除的行数:

count=`wc -l file`
lines=`expr "$count" - n`
head -n "$lines" file > temp.txt
mv temp.txt file
rm -f temp.txt

这有点回旋处,但我认为它很容易遵循。

  1. 计算主文件中的行数
  2. 减去要从计数中删除的行数
  3. 打印出您要保留的行数并将其存储在临时文件中
  4. 用临时文件替换主文件
  5. 删除临时文件

0

要删除文件的最后N行,可以使用相同的概念

$ sed '2,4d' file

您可以使用带tail的组合命令来反转文件:如果N为5

$ tail -r file | sed '1,5d' file | tail -r > file

而且这种方式也可以在head -n -5 file不运行命令的地方运行(例如在Mac上!)。


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.