繁体   English   中英

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

[英]Remove the last line from a file in Bash

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

a
b
c

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

a
b

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

操作系统:

在 Mac OS X(从 10.7.4 开始)上,相当于上面的sed -i命令是

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

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

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

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

tail -n +2 foo.txt

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

不要使用sed从文件的顶部或底部删除行——如果文件很大,它会非常慢。

对于大文件

我在这里的所有答案都遇到了麻烦,因为我正在处理一个巨大的文件(~300Gb)并且没有一个解决方案可以扩展。 这是我的解决方案:

filename="example.txt"

file_size="$(stat --format=%s "$filename")"
trim_count="$(tail -n1 "$filename" | wc -c)"
end_position="$(echo "$file_size - $trim_count" | bc)"

dd if=/dev/null of="$filename" bs=1 seek="$end_position"

或者,作为单衬:

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

用字词:找出您想要结束的文件的长度(文件的长度减去其最后一行的长度,使用bc ),并将该位置设置为文件的末尾(通过dd ing 一个字节/dev/null到它)。

这很快,因为tail从末尾开始读取,而dd将覆盖文件原地,而不是复制(和解析)文件的每一行,这是其他解决方案所做的。

注意:这会从文件中删除该行! 在您自己的文件上尝试之前,请先备份或测试一个虚拟文件!

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

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

要删除最后一行并将其打印在标准输出上(“弹出”它),您可以将该命令与tee结合使用:

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

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

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

对于 Mac 用户:

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

我尝试了以下命令序列,很高兴我可以只使用“tail”命令 [ 使用 Mac 上可用的选项 ] 来解决它。 所以,如果你在 Mac 上,并且只想使用“tail”来解决这个问题,你可以使用这个命令:

猫文件.txt | 尾巴 -r | 尾 -n +2 | 尾-r

说明:

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

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

Mac 用户

如果您只想删除最后一行的输出而不更改文件本身

sed -e '$ d' foo.txt

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

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

echo -e '$d\nw\nq'| ed foo.txt
awk 'NR>1{print buf}{buf = $0}'

本质上,这段代码说明如下:

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

对于每一行,重置缓冲区

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

Linux

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

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

操作系统

相当于 sed -i

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

这是使用海绵的解决方案(来自moreutils包):

head -n -1 foo.txt | sponge foo.txt

解决方案总结:

  1. 如果您想快速解决大文件,请使用高效的 taildd方法。

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

  3. 如果你想要一些易于扩展/调整的东西,文件不是太大,便携性(即,取决于moreutils包)不是问题,而且你是方裤的粉丝,可以考虑海绵方法。

与“重定向和移动”方法相比,海绵方法的一个很好的好处是海绵保留了文件权限。

与“重定向和移动”方法相比,Sponge 使用了更多的 RAM。 这会提高一点速度(只有大约 20%),但是如果您对速度感兴趣,那么“高效尾部”和 dd 方法是要走的路。

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

这个片段可以解决问题。

这两种解决方案都以其他形式存在。 我发现这些更实用、更清晰、更有用:

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

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

vim + [FILE]

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

现在只需在键盘上按d两次即可。 这将完全符合您的要求——删除最后一行。 之后,按:然后按x然后按Enter 这将保存更改并使您返回到 shell。 现在,最后一行已成功删除。

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

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

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

可以处理大量数据并且输出还可以,但是有一条垃圾线。

如果我将脚本的输出通过管道传输到:

| sed -i '$ d' 我会得到以下错误,最后根本没有输出 sed: no input files

但是| head -n -1 有效!

红宝石(1.9+)

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM