Bashのファイルから最後の行を削除する


回答:


408

使用GNU sed

sed -i '$ d' foo.txt

この-iオプションはGNU sed3.95より前のバージョンには存在しないため、一時ファイルのフィルターとして使用する必要があります。

cp foo.txt foo.txt.tmp
sed '$ d' foo.txt.tmp > foo.txt
rm -f foo.txt.tmp

もちろん、その場合はのhead -n -1代わりに使用することもできますsed

マックOS:

Mac OS X(10.7.4以降)では、sed -i上記のコマンドと同等です。

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

56
Mac OS X(10.7.4以降)では、sed -i上記のコマンドと同等ですsed -i '' -e '$ d' foo.txt。また、head -n -1現在Macでは動作しません。
mklement0

26
'$ d'正規表現の機能を説明していただけますか?最後の行を削除することについての質問なので、この質問を表示するすべての人にとって、これは最も重要な部分だと思います。おかげで:)
クラベミール2013年

38
@Miro:$ d正規表現ではありません。sedコマンドです。d行を削除するコマンドですが、$「ファイルの最後の行」を意味します。コマンドの前に場所(sed lingoでは「範囲」と呼ばれます)を指定すると、そのコマンドは指定された場所にのみ適用されます。したがって、このコマンドは「ファイルの最終行の範囲で、それを削除する」と明示的に言っています。あなたが私に尋ねるなら、かなり滑らかでまっすぐなポイントです。
Daniel Kamil Kozar 2014年

1
最後の行を削除するにはどうすればよいですか(空の行の場合のみ)。
skan

1
@Alex:GNU sed用に更新。さまざまなBSD / UNIX / MacOS sedバージョンについては
わかりませ

279

これは、特に大きなファイルの場合、断然最速かつ最も簡単なソリューションです。

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

あなたが一番上の行を削除したいなら、これを使ってください:

tail -n +2 foo.txt

これは、2行目から始まる出力行を意味します。

sedファイルの上部または下部から行を削除する場合は使用しないでください。ファイルが大きい場合は非常に遅くなります。


16
head -n -1 foo.txt十分です
ДМИТРИЙМАЛИКОВ

20
head -n -1はbdsutilsの頭では機能しません。macosが使用しているバージョンでは少なくとも、これは機能しません。
johannes_lalala

23
@johannes_lalala Macでは、の代わりにbrew install coreutils(GNUコアユーティリティ)を使用できます。gheadhead
興味深いことに

下に行数が異なる複数のファイルを削除する場合に自動化する簡単なbashスクリプトを次に示しFILE=$1; TAIL=$2; head -n -${TAIL} ${FILE} > temp ; mv temp ${FILE}ます。cat TAILfixer ./TAILfixer myfile 4次のようにmyfileからたとえば4行を削除するために実行します。もちろん、最初に実行可能にしますchmod +x TAILfixer
FatihSarigol

効果があったのでいいのですが、との比較ではsed、このコマンドもかなり遅いです
Jeff Diederiks '31

121

私はここですべての答えに問題がありました。なぜなら、私は巨大なファイル(〜300Gb)で作業していて、ソリューションのスケーリングが行われていないためです。これが私の解決策です:

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

つまり、最終的に必要なファイルの長さ(ファイルの長さから最後の行の長さを引いて、を使用bc)を見つけ、その位置をファイルの最後に設定します(dd1バイト /dev/nullをそれ)。

これは高速でtail起動すると端から読み取り、ddファイルが上書きされます代わりにし、他のソリューションが何であるファイルのすべての行をコピー(および解析)するのではなく。

注:これにより、ファイルから行が削除されます!自分のファイルで試す前に、ダミーファイルでバックアップまたはテストしてください!


3
私もddについて知りませんでした。これが一番の答えになるはずです。どうもありがとうございます!ソリューションが(ブロック)gzip圧縮ファイルに対して機能しないのは残念です。
tommy.carstensen 2014

4
とても、とても賢いアプローチです!ただ注意:それは実際のファイルを必要とし、操作するので、パイプ、コマンドの置換、リダイレクト、およびそのようなチェーンでは使用できません。
MestreLion 2015

3
これが一番の答えになるはずです。〜8 GBのファイルをすぐに処理できました。
Peter Cogan

8
Macユーザー:dd if = / dev / null of = <filename> bs = 1 seek = $(echo $(stat -f =%z <filename> | cut -c 2-)-$(tail -n1 <filename> | wc -c)| bc)
Igor

2
このアプローチは、大きなファイルを処理する方法です。
thomas.han 2017

61

ファイルの最後の行を削除するには、ファイル全体を読んだり、何かを書き換えることなく、あなたが使用することができます

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

最後の行を削除してstdoutに出力する(「ポップする」)には、次のコマンドを組み合わせますtee

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

これらのコマンドは、非常に大きなファイルを効率的に処理できます。これはYossiの回答に似ており、それに触発されていますが、いくつかの追加機能の使用を回避しています。

これらを繰り返し使用してエラー処理やその他の機能が必要な場合は、httpspoptail//github.com/donm/evenmoreutilsのコマンド を使用できます


3
クイックノート:truncateOS Xではデフォルトでは使用できません。しかし、Brew:を使用してインストールするのは簡単ですbrew install truncate
Guillaume Boudreau 2016

3
非常に素晴らしい。ddなしではるかに良い。私はddを1つの誤った数字または文字が災害を
引き起こす

1
(ジョーク警告)実際、( "dd"-> "disaster")には1つの置換と6つの挿入が必要です。「1つの誤った数字または文字」はほとんどありません。:)
カイル

29

Macユーザー

ファイル自体を変更せずに最後の行の出力のみを削除したい場合

sed -e '$ d' foo.txt

入力ファイル自体の最後の行を削除したい場合

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


これでうまくいきますが、わかりません。とにかく、それは働いた。
メルビン

このフラグ-i ''は、パラメーターとして提供された拡張子を持つファイルにバックアップを保持しながら、ファイルをインプレースで変更するようにsedに指示します。パラメータは空の文字列であるため、バックアップファイルは作成されません。-eコマンドを実行するようにsedに指示します。コマンドの$ d意味:最後の行を見つけ($)、それを削除します(d)。
Krzysztof Szafranek

24

Macユーザーの場合:

Macでは、head -n -1は機能しません。そして、「処理時間を気にすることなく」、「head」または「tail」コマンドのみを使用してこの問題を解決する簡単な解決策を見つけようとしていました。

私は次の一連のコマンドを試してみましたが、[Macで利用可能なオプションを使用して] "tail"コマンドを使用するだけでそれを解決できて嬉しかったです。したがって、Macを使用していて、「tail」のみを使用してこの問題を解決したい場合は、次のコマンドを使用できます。

cat file.txt | テール-r | 尾-n +2 | 尾-r

説明 :

1> tail -r:入力の行の順序を逆にします

2> tail -n +2:入力の2行目から始まるすべての行を出力します


2
自作を使用してインストールcoreutilsのは、あなたがすることができ、「ghead」としてあなたのGNUの頭を与えるだろうghead -n -1
somewhatoff

13
echo -e '$d\nw\nq'| ed foo.txt

2
その場でファイルを編集しないフィルターソリューションの場合は、を使用しますsed '$d'
lhf

8
awk 'NR>1{print buf}{buf = $0}'

基本的に、このコードは次のように述べています。

1行目以降の各行について、バッファリングされた行を印刷します

行ごとに、バッファをリセットします

バッファは1行遅れているため、1行目からn-1行目までが出力されます。


2
この解決策はフィルターであり、ファイルを編集しません。
lhf


0

これらのソリューションはどちらも他の形式で提供されています。私はこれらがもう少し実用的で、明確で、有用であるとわかりました:

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}

痛い。複雑すぎる。
Robert


0

これを手動で行う方法は次のとおりです(個人的にこの方法は、ファイルの最後の行をすばやく削除する必要がある場合に頻繁に使用します)。

vim + [FILE]

その+記号は、ファイルがvimテキストエディタで開かれると、カーソルがファイルの最終行に置かれることを意味します。

dキーボードを2回押します。これにより、希望どおりの結果が得られます。最終行を削除してください。その後、プレスが:続いxた後、プレスEnter。これにより変更が保存され、シェルに戻ります。これで、最後の行が正常に削除されました。


2
ここではシンプルさの強調が失われました
Peter M

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.