从Bash中的文件中删除最后一行


Answers:


406

使用GNU sed

sed -i '$ d' foo.txt

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

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

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

苹果系统:

在Mac OS X(自10.7.4版)上,上述sed -i命令等效于

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

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

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

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

1
仅当它是空行时,如何删除最后一行?
skan,

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

279

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

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

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

tail -n +2 foo.txt

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

请勿sed用于删除文件顶部或底部的行-如果文件很大,这将非常慢。


16
head -n -1 foo.txt
ДМИТРИЙМАЛИКОВ

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

23
@johannes_lalala在Mac上,您可以brew install coreutils(GNU核心实用程序)使用ghead而不是head
有趣的是

下面是一个简单的bash脚本,它可以自动它的情况下,你在底部有不同数量的行多个文件删除:猫TAILfixer FILE=$1; TAIL=$2; head -n -${TAIL} ${FILE} > temp ; mv temp ${FILE}运行它删除4条线路,例如从MYFILE为:./TAILfixer myfile 4当然首先要成为可执行chmod +x TAILfixer
FatihSarigol

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

121

我在这里遇到的所有答案都遇到了麻烦,因为我正在使用巨大的文件(〜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会覆盖原位文件而不是复制(和解析)文件的每一行,这是其他解决方案所做的。

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


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

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

3
这应该是最佳答案。立即为我的〜8 GB文件工作。
彼得·科根

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

2
这种方法是处理大文件的方法!
thomas.han

61

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

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

要删除最后一行并在stdout上打印(“弹出”它),可以将该命令与tee

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

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

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


3
快速说明:truncate默认情况下在OS X上不可用。但是使用Brew:安装很容易brew install truncate
纪尧姆·布德罗

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

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

29

Mac用户

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

sed -e '$ d' foo.txt

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

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


这对我有用,但我听不懂。无论如何,它奏效了。
梅尔文(Melvin)

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

24

对于Mac用户:

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

我尝试了以下命令序列,并很高兴我可以仅使用“ tail”命令(使用Mac上的可用选项)来解决它。因此,如果您使用的是Mac,并且只想使用“ tail”来解决此问题,则可以使用以下命令:

猫file.txt | 尾-r | 尾-n +2 | 尾巴

说明:

1> tail -r:简单地反转其输入中的行顺序

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


2
使用Homebrew安装coreutils将为您提供GNU的“ ghead”头,允许您这样做ghead -n -1
有点

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

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

8
awk 'NR>1{print buf}{buf = $0}'

本质上,此代码说明以下内容:

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

对于每一行,重置缓冲区

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


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


0

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

使用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}

哎哟。方式太复杂了。
罗伯特

0

的Linux

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

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

苹果系统

相当于sed -i

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

0

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

vim + [FILE]

+符号表示在vim文本编辑器中打开文件时,光标将位于文件的最后一行。

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


2
在强调简洁被丢在这里
彼得·中号

-4

红宝石(1.9+)

ruby -ne 'BEGIN{prv=""};print prv ; prv=$_;' file
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.