[英]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 上, 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 行
sed '$d' ~/path/to/your/file/name
sed -i '' -e '$ d' ~/path/to/your/file/name
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.