我有一个文件,foo.txt,包含以下行:
a
b
c
我想要一个简单的命令,导致foo.txt的内容为:
a
b
我有一个文件,foo.txt,包含以下行:
a
b
c
我想要一个简单的命令,导致foo.txt的内容为:
a
b
当前回答
Linux
$表示最后一行,d表示删除:
sed '$d' ~/path/to/your/file/name
操作系统
相当于sed -i:
sed -i '' -e '$ d' ~/path/to/your/file/name
其他回答
awk 'NR>1{print buf}{buf = $0}'
本质上,这段代码表示:
对于第一行之后的每一行,打印缓冲行
对于每一行,重置缓冲区
缓冲区延迟了一行,因此最终打印的是第1行到第n-1行
对于大文件
我在这里遇到了所有答案的麻烦,因为我正在使用一个巨大的文件(~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),并将该位置设置为文件的结束位置(通过在其上添加/dev/null的一个字节)。
这是快速的,因为tail从末尾开始读取,dd将就地覆盖文件,而不是复制(并解析)文件的每一行,这是其他解决方案所做的。
注意:这将删除文件中的行!在对自己的文件进行备份或测试之前,先对虚拟文件进行备份或测试!
这两个解都是另一种形式。我发现下面这些更实际、更清晰、更有用:
使用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}
awk "NR != `wc -l < text.file`" text.file &> newtext.file
这段代码可以达到目的。
这是目前为止最快和最简单的解决方案,特别是对大文件:
head -n -1 foo.txt > temp.txt ; mv temp.txt foo.txt
如果你想删除顶部行,使用这个:
tail -n +2 foo.txt
这意味着输出行从第2行开始。
不要使用sed从文件的顶部或底部删除行——如果文件很大,它会非常非常慢。