我有一个文件foo.txt,其中包含以下几行:

a
b
c


我想要一个简单的命令,该命令导致foo.txt的内容为:

a
b


#1 楼

使用GNU sed

sed -i '$ d' foo.txt


-i版本在3.95之前的版本中不存在GNU sed选项,因此您必须将其用作带有临时文件的过滤器:

cp foo.txt foo.txt.tmp
sed '$ d' foo.txt.tmp > foo.txt
rm -f foo.txt.tmp


当然,在这种情况下,您也可以使用head -n -1而不是sed

MacOS:

在Mac OS上X(从10.7.4版本开始),与上述sed -i命令的等效项为

sed -i '' -e '$ d' foo.txt


评论


在Mac OS X上(自10.7.4起),与sed -i命令等效的是sed -i''-e'$ d'foo.txt。另外,head -n -1目前在Mac上无法使用。

–mklement0
2012年6月8日在22:15

您能解释一下'$ d'正则表达式的作用吗?这是关于删除最后一行的问题,所以我认为这对于每个查看此问题的人来说都是最重要的部分。谢谢 :)

– Kravemir
13年4月4日在12:47

@Miro:$ d绝对不是正则表达式。这是一个sed命令。 d是删除行的命令,而$表示“文件中的最后一行”。在命令前指定位置(在sed lingo中称为“范围”)时,该命令仅应用于指定位置。因此,此命令明确表示“在文件的最后一行的范围内,将其删除”。如果您要我的话,很滑而直截了当。

–丹尼尔·卡米尔·科扎尔(Daniel Kamil Kozar)
2014年6月4日在8:37



仅当空行时,如何删除最后一行?

– skan
17年1月16日在11:09

@Alex:已针对GNU sed更新;不知道各种BSD / UNIX / MacOS sed版本...

– thkala
17年1月23日在21:44

#2 楼

这是迄今为止最快,最简单的解决方案,尤其是在大文件上:

head -n -1 foo.txt > temp.txt ; mv temp.txt foo.txt


如果要删除顶行,请使用以下命令:

tail -n +2 foo.txt


,这意味着输出行从第2行开始。

请勿使用sed删除文件顶部或底部的行-如果文件很大。

评论


头-n -1 foo.txt就足够了

–ДМИТРИЙМАЛИКОВ
13年4月19日在23:57

head -n -1在bdsutils的head上不起作用。至少在macos使用的版本中不这样,所以这不起作用。

– johannes_lalala
15年1月22日在11:49

@johannes_lalala在Mac上,您可以brew安装coreutils(GNU核心实用程序)并使用ghead代替head。

–有趣的是
15年8月10日在14:12

这是一个简单的bash脚本,当您有多个文件的底部要删除的行数不同时,该脚本可以自动执行以下操作:cat TAILfixer FILE = $ 1; TAIL = $ 2; head -n-$ {TAIL} $ {FILE}> temp; mv temp $ {FILE}运行它以从myfile中删除4行,例如:./TAILfixer myfile 4首先要使其通过chmod + x TAILfixer可执行。

–法提赫·萨里戈尔(FatihSarigol)
18-3-28在21:11



竖起大拇指是因为它起作用了,但是对于所有与sed的比较,该命令也相当慢

– Jeff Diederiks
18年5月31日在15:32

#3 楼

我在这里遇到的所有问题都遇到了麻烦,因为我正在使用巨大的文件(〜300Gb),并且没有一种解决方案可以扩展。这是我的解决方案:

dd if=/dev/null of=<filename> bs=1 seek=$(echo $(stat --format=%s <filename> ) - $( tail -n1 <filename> | wc -c) | bc )


换句话说:找出要结束的文件的长度(文件长度减去最后一行的长度,使用bc),并将该位置设置为文件的末尾(通过dd/dev/null的一个字节写入文件的末尾)。

这是快速的,因为tail从头开始读取,并且dd会覆盖文件,而不是复制(和解析)文件的每一行,这是其他解决方案所做的。

注意:这会将行从文件中删除!在尝试对自己的文件进行备份之前,请对虚拟文件进行备份或测试!

评论


我什至不知道dd。这应该是最佳答案。非常感谢!遗憾的是,该解决方案不适用于(阻止)压缩文件。

–tommy.carstensen
2014-09-25 11:46

非常非常聪明的方法!请注意:它需要并在真实文件上运行,因此不能在管道,命令替换,重定向和此类链上使用。

–MestreLion
15年8月30日在11:37

这应该是最佳答案。立即为我的〜8 GB文件工作。

– Peter Cogan
16年1月9日在21:08

Mac用户:dd if = / dev / null of = <文件名> bs = 1 seek = $(echo $(stat -f =%z <文件名> | cut -c 2-)-$(tail -n1 <文件名> | wc -c)| bc)

–伊戈尔
16-4-5在14:49



这种方法是处理大文件的方法!

–thomas.han
17年8月3日,下午5:53

#4 楼

要从文件中删除最后一行而不读取整个文件或重写任何内容,可以使用

tail -n 1 "$file" | wc -c | xargs -I {} truncate "$file" -s -{}


删除最后一行并在stdout上打印它(“ pop”),则可以将该命令与tee结合使用:

tail -n 1 "$file" | tee >(wc -c | xargs -I {} truncate "$file" -s -{})


这些命令可以有效地处理非常大的文件。这与Yossi的答案相似并受其启发,但是避免了使用一些额外的功能。

如果您要重复使用这些功能并且想要错误处理和其他一些功能,则可以在此处使用poptail命令:
https://github.com/donm/evenmoreutils

评论


快速说明:截断默认情况下在OS X上不可用。但是使用Brew进行安装很容易:brew install tr​​uncate。

–纪尧姆·布德罗(Guillaume Boudreau)
16年2月1日在20:44

非常好。没有dd会更好。我对将dd用作单个错位的数字或字母会造成灾难表示恐惧。.+1

–尤西·法琼(Yossi Farjoun)
16年6月12日在5:30

(笑话)实际上,(“ dd”->“ disaster”)需要1次替换和6次插入;几乎不是“单个错位的数字或字母”。 :)

–凯尔
18年5月23日在21:20

#5 楼


Mac用户


如果只希望最后一行删除输出而不更改文件本身,请这样做

sed -e '$ d' foo.txt

如果要删除输入文件本身的最后一行,请执行

sed -i '' -e '$ d' foo.txt

评论


这对我有用,但我听不懂。无论如何,它奏效了。

–梅尔文
18-10-11在12:04

标志-i''指示sed在就地修改文件的同时,将备份保留在文件中,并将扩展名作为参数提供。由于该参数为空字符串,因此不会创建备份文件。 -e告诉sed执行命令。命令$ d的意思是:找到最后一行($)并删除它(d)。

– Krzysztof Szafranek
19 Mar 3 '19 at 14:05



#6 楼

对于Mac用户:

在Mac上,头-n -1不起作用。而且,我试图找到一种简单的解决方案[无需担心处理时间]仅使用“ head”和/或“ tail”命令来解决此问题。

我尝试了以下命令顺序,我很高兴我可以使用“ tail”命令(使用Mac上的可用选项)解决此问题。因此,如果您使用的是Mac,并且只想使用“ tail”来解决此问题,则可以使用以下命令:cat file.txt |尾-r |尾-n +2 | tail -r


说明:

1> tail -r:仅颠倒其输入中的行顺序

2> tail -n +2:这将从输入中的第二行开始打印所有行

评论


使用Homebrew安装coreutils将为您提供GNU头为“ ghead”,使您可以进行ghead -n -1

–有点不对劲
18 Mar 9 '18 at 15:31

#7 楼

echo -e '$d\nw\nq'| ed foo.txt


评论


对于未在适当位置编辑文件的过滤器解决方案,请使用sed'$ d'。

–lhf
2011年2月3日,下午1:59

#8 楼

awk 'NR>1{print buf}{buf = q4312078q}'


本质上,该代码表示​​以下内容:

对于第一行之后的每一行,打印缓冲行

,为每行重置缓冲区

缓冲区滞后了一行,因此您最终将第1行打印到n-1

评论


此解决方案是一个筛选器,不会在适当位置编辑文件。

–lhf
2011年2月3日,下午1:58

#9 楼

Linux

$是最后一行,d表示删除:

sed '$d' ~/path/to/your/file/name


MacOS

与sed等效- i

sed -i '' -e '$ d' ~/path/to/your/file/name


#10 楼

awk "NR != `wc -l < text.file`" text.file |> text.file


这个代码可以解决问题。

评论


这只是为我删除了整个文件。

– Kartik Chugh
20年5月6日在17:21

#11 楼

这两种解决方案都以其他形式出现。我发现这些更加实用,清晰和有用:

使用dd:

BADLINESCOUNT=1
ORIGINALFILE=/tmp/whatever
dd if=${ORIGINALFILE} of=${ORIGINALFILE}.tmp status=none bs=1 count=$(printf "$(stat --format=%s ${ORIGINALFILE}) - $(tail -n${BADLINESCOUNT} ${ORIGINALFILE} | wc -c)\n" | bc )
/bin/mv -f ${ORIGINALFILE}.tmp ${ORIGINALFILE}


使用截断:

BADLINESCOUNT=1
ORIGINALFILE=/tmp/whatever
truncate -s $(printf "$(stat --format=%s ${ORIGINALFILE}) - $(tail -n${BADLINESCOUNT} ${ORIGINALFILE} | wc -c)\n" | bc ) ${ORIGINALFILE}


评论


哎哟。方式太复杂了。

–罗伯特
19年1月6日在23:22

#12 楼

手动操作的方法如下(当我需要快速删除文件的最后一行时,我个人经常使用此方法):

vim + [FILE]


那个+在那里签名表示在vim文本编辑器中打开文件时,光标将位于文件的最后一行。

现在只需在键盘上按d两次。这将完全满足您的要求-删除最后一行。之后,按:,然后按x,然后按Enter。这将保存更改并将您带回外壳。现在,最后一行已成功删除。

评论


这里没有强调简单性

–彼得
19/12/27在13:02



#13 楼

您也可以尝试这种方法:删除最后n行的示例。

a = 0; while [$ a -lt 4]; sed -i'$ d'output.txt; a = expr $a + 1;完成

从文件(output.txt)中删除最后4行。

#14 楼

以下是使用海绵的解决方案(来自moreutils软件包):
head -n -1 foo.txt | sponge foo.txt

解决方案摘要:


如果您想要快速解决大型文件的问题,请使用高效的尾巴或dd方法。


如果您想要一些易于扩展/调整和便携的方法,请使用重定向和移动方法。


如果您想要一些易于扩展/调整的东西,文件不要太大,可移植性(即取决于moreutils包)不是问题,并且您是方形裤子的粉丝,请考虑使用海绵方法。


与“重定向和移动”方法相比,海绵方法的一个好处是海绵可以保留文件权限。
与“重定向和移动”方法相比,海绵使用的内存要多得多。这样可以提高速度(仅约20%),但是如果您对速度感兴趣,则可以使用“有效尾巴”和dd方法。

#15 楼

Ruby(1.9+)

ruby -ne 'BEGIN{prv=""};print prv ; prv=$_;' file