我有一个文件,foo.txt,包含以下行:
foo.txt
a b c
我想要一个简单的命令,导致foo.txt的内容为:
a b
awk 'NR>1{print buf}{buf = $0}'
本质上,这段代码表示:
对于第一行之后的每一行,打印缓冲行
对于每一行,重置缓冲区
缓冲区延迟了一行,因此最终打印的是第1行到第n-1行
echo -e '$d\nw\nq'| ed foo.txt
使用GNU sed:
GNU sed
sed -i '$ d' foo.txt
-i选项在3.95以上的GNU sed版本中不存在,所以你必须使用它作为一个临时文件的过滤器:
-i
cp foo.txt foo.txt.tmp sed '$ d' foo.txt.tmp > foo.txt rm -f foo.txt.tmp
当然,在这种情况下,你也可以使用head -n -1而不是sed。
head -n -1
sed
MacOS:
在Mac OS X(截至10.7.4)上,与上面的sed -i命令等价的是
sed -i
sed -i '' -e '$ d' foo.txt
Ruby (1.9 +)
ruby -ne 'BEGIN{prv=""};print prv ; prv=$_;' file
这是目前为止最快和最简单的解决方案,特别是对大文件:
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),并将该位置设置为文件的结束位置(通过dding /dev/null的一个字节到它上面)。
bc
dd
/dev/null
这是快速的,因为tail从末尾开始读取,并且dd将覆盖文件在适当的位置,而不是复制(并解析)文件的每一行,这是其他解决方案所做的。
tail
注意:这将删除文件中的行!在对自己的文件进行备份或测试之前,先对虚拟文件进行备份或测试!
要从文件不需要阅读整个文件或重写任何东西中删除最后一行,可以使用
tail -n 1 "$file" | wc -c | xargs -I {} truncate "$file" -s -{}
要删除最后一行并将其打印到stdout(“弹出”它),可以将该命令与tee结合使用:
tee
tail -n 1 "$file" | tee >(wc -c | xargs -I {} truncate "$file" -s -{})
这些命令可以有效地处理一个非常大的文件。这与Yossi的答案相似,并受到了启发,但它避免了使用一些额外的函数。
poptail
Mac用户
如果只希望删除最后一行输出而不更改文件本身做
sed -e '$ d' foo.txt
如果要删除输入文件本身的最后一行
awk "NR != `wc -l < text.file`" text.file &> newtext.file
这段代码可以达到目的。
在macOS上,head -n -1不能工作,但是你可以使用这个命令:
cat file.txt | tail -r | tail -n +2 | tail -r
tail -r将其输入中的行顺序颠倒
tail -r
tail -n +2打印输入中从第二行开始的所有行
tail -n +2
这两个解都是另一种形式。我发现下面这些更实际、更清晰、更有用:
使用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}
sed '$d' ~/path/to/your/file/name
sed -i '' -e '$ d' ~/path/to/your/file/name
你也可以试试这个方法:删除最后n行数的例子。
= 0;While [$a -lt 4];do sed -i '$ d' output.txt;一个= expr $a + 1;完成
expr $a + 1
删除文件(output.txt)的最后4行。
下面是一个使用海绵的解决方案(来自moreutils包):
head -n -1 foo.txt | sponge foo.txt
解决方案总结:
moreutils
与“重定向和移动”相比,海绵方法的一个很好的好处是;方法,是海绵保存文件权限。
与“重定向和移动”相比,“海绵”使用的RAM要多得多。的方法。这增加了一点速度(只有大约20%),但如果你对速度感兴趣,“高效尾部”;dd方法是可行的。
OK处理了大量的数据,输出是OK的,但有一个垃圾行。
如果我用管道输出脚本到:
| sed -i '$ d'我会得到以下错误,最后根本没有输出 Sed: no input files
但是|头-n -1成功了!