问题
I have a file, foo.txt
, containing the following lines:
a
b
c
I want a simple command that results in the contents of foo.txt
being:
a
b
回答1:
Using GNU sed:
sed -i '$ d' foo.txt
The -i
option does not exist in GNU sed
versions older than 3.95, so you have to use it as a filter with a temporary file:
cp foo.txt foo.txt.tmp
sed '$ d' foo.txt.tmp > foo.txt
rm -f foo.txt.tmp
Of course, in that case you could also use head -n -1
instead of sed
.
MacOS:
On Mac OS X (as of 10.7.4), the equivalent of the sed -i
command above is
sed -i '' -e '$ d' foo.txt
回答2:
This is by far the fastest and simplest solution, especially on big files:
head -n -1 foo.txt > temp.txt ; mv temp.txt foo.txt
if You want to delete the top line use this:
tail -n +2 foo.txt
which means output lines starting at line 2.
Do not use sed
for deleting lines from the top or bottom of a file -- it's very very slow if the file is large.
回答3:
I had trouble with all the answers here because I was working with a HUGE file (~300Gb) and none of the solutions scaled. Here's my solution:
dd if=/dev/null of=<filename> bs=1 seek=$(echo $(stat --format=%s <filename> ) - $( tail -n1 <filename> | wc -c) | bc )
In words: Find out the length of the file you want to end up with (length of file minus length of length of its last line, using bc
) and, set that position to be the end of the file (by dd
ing one byte of /dev/null
onto it).
This is fast because tail
starts reading from the end, and dd
will overwrite the file in place rather than copy (and parse) every line of the file, which is what the other solutions do.
NOTE: This removes the line from the file in place! Make a backup or test on a dummy file before trying it out on your own file!
回答4:
To remove the last line from a file without reading the whole file or rewriting anything, you can use
tail -n 1 "$file" | wc -c | xargs -I {} truncate "$file" -s -{}
To remove the last line and also print it on stdout ("pop" it), you can combine that command with tee
:
tail -n 1 "$file" | tee >(wc -c | xargs -I {} truncate "$file" -s -{})
These commands can efficiently process a very large file. This is similar to, and inspired by, Yossi's answer, but it avoids using a few extra functions.
If you're going to use these repeatedly and want error handling and some other features, you can use the poptail
command here:
https://github.com/donm/evenmoreutils
回答5:
Mac Users
if you only want the last line deleted output without changing the file itself do
sed -e '$ d' foo.txt
if you want to delete the last line of the input file itself do
sed -i '' -e '$ d' foo.txt
回答6:
For Mac Users :
On Mac, head -n -1 wont work. And, I was trying to find a simple solution [ without worrying about processing time ] to solve this problem only using "head" and/or "tail" commands.
I tried the following sequence of commands and was happy that I could solve it just using "tail" command [ with the options available on Mac ]. So, if you are on Mac, and want to use only "tail" to solve this problem, you can use this command :
cat file.txt | tail -r | tail -n +2 | tail -r
Explanation :
1> tail -r : simply reverses the order of lines in its input
2> tail -n +2 : this prints all the lines starting from the second line in its input
回答7:
echo -e '$d\nw\nq'| ed foo.txt
回答8:
awk 'NR>1{print buf}{buf = $0}'
Essentially, this code says the following:
For each line after the first, print the buffered line
for each line, reset the buffer
The buffer is lagged by one line, hence you end up printing lines 1 to n-1
回答9:
awk "NR != `wc -l < text.file`" text.file |> text.file
This snippet does the trick.
回答10:
Both of these solutions are here in other forms. I found these a little more practical, clear, and useful:
Using 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}
Using truncate:
BADLINESCOUNT=1
ORIGINALFILE=/tmp/whatever
truncate -s $(printf "$(stat --format=%s ${ORIGINALFILE}) - $(tail -n${BADLINESCOUNT} ${ORIGINALFILE} | wc -c)\n" | bc ) ${ORIGINALFILE}
回答11:
Here's how your can do it manually (I personally use this method a lot when I need to quickly remove the last line in a file):
vim + [FILE]
That +
sign there means that when the file is opened in the vim text editor, the cursor will be positioned on the last line of the file.
Now just press d
twice on your keyboard. This will do exactly what you want—remove the last line. After that, press :
followed by x
and then press Enter
. This will save the changes and bring you back to the shell. Now, the last line has been successfully removed.
回答12:
Linux
$ is the last line, d for delete:
sed '$d' ~/path/to/your/file/name
MacOS
Equivalent of the sed -i
sed -i '' -e '$ d' ~/path/to/your/file/name
回答13:
Ruby(1.9+)
ruby -ne 'BEGIN{prv=""};print prv ; prv=$_;' file
来源:https://stackoverflow.com/questions/4881930/remove-the-last-line-from-a-file-in-bash