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

Remove the last line from a file in Bash

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

1
2
3
a
b
c

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

1
2
a
b

使用GNU sed

1
sed -i '$ d' foo.txt

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

1
2
3
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命令等效

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


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

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

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

1
tail -n +2 foo.txt

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

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


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

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

换句话说:找出要结束的文件的长度(文件长度减去最后一行的长度,使用bc),并将该位置设置为文件的结尾(/dev/null的一个字节添加到其上)。

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

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


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

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

要删除最后一行并在stdout上打印("弹出"它),可以将该命令与tee结合使用:

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

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

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


Mac Users

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

sed -e '$ d' foo.txt

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

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


对于Mac用户:

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

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

cat file.txt | tail -r | tail -n +2 | tail -r

说明:

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

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


1
2
3
echo -e '$d
w
q'
| ed foo.txt


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

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

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

对于每一行,重置缓冲区

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


的Linux

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

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

苹果系统

相当于sed -i

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

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

1
vim + [FILE]

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

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


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

使用dd:

1
2
3
4
5
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)
"
| bc )
/bin/mv -f ${ORIGINALFILE}.tmp ${ORIGINALFILE}

使用截断:

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


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

此代码片段可以解决问题。


红宝石(1.9+)

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