「tail」と「head」の逆の動作を取得する方法は?


55

ドキュメントにhead/ tail逆方向の出力を取得する方法はありますか?文書に何行あるかわからないからですか?

すなわち、最初の2行foo.txtを除いてすべてを取得して、別のドキュメントに追加するだけです。

回答:


57

これを使用して、最初の 2行を削除できます。

tail -n +3 foo.txt

最後の 2行を削除するには、次のようにします。

head -n -2 foo.txt

(ファイルの末尾が\n後者の場合)


ただの標準的な使用のために好きtailheadこれらの操作は破壊的ではありません。>out.txt出力を新しいファイルにリダイレクトする場合に使用します。

tail -n +3 foo.txt >out.txt

out.txtすでに存在する場合、このファイルは上書きされます。出力をに追加する場合の>>out.txt代わりに使用>out.txtout.txtます。


3
re "head、when end file \n" .. (head:(GNU coreutils)7.4を使用)のように、何も-n -0返さない以外のすべての負の整数で動作します-n 0...しかし、末尾\nが存在する場合、-n -0印刷しますから予想されるように-、すなわち。それはファイル全体を印刷し...だから、すべての非ゼロの負の値のために働くん..しかし、-0末尾がない場合に失敗する\n
Peter.O

@fred:確かに奇妙な…(ここで8.12と同じ)。
ステファンギメネス

この操作は破壊的ですか?文書の最初の2行の逆を別の行にコピーしたいですか?
chrisjlee

@Chris:いいえ、彼らは「標準出力」に結果を印刷するだけで、通常は端末に接続されています。出力をいくつかのファイルにリダイレクトする方法に関する詳細を追加しました。
ステファンギメネス

7
head -n -2POSIX互換ではありません。
l0b0

9

最初のN-1行を除くすべての行が必要な場合tailは、行数で呼び出します+N。(番号は、保持する最初の行の番号で、1から始まります。つまり、+ 1は先頭から始まり、+ 2は1行スキップすることを意味します)。

tail -n +3 foo.txt >>other-document

最後のN行をスキップする簡単でポータブルな方法はありません。GNU headhead -n +N、の対応物として許可していtail -n +Nます。それ以外の場合tac(GNUやBusyboxなど)がある場合は、tailと組み合わせることができます。

tac | tail -n +3 | tac

移植可能であれば、awkフィルター(未テスト)を使用できます。

awk -vskip=2 '{
    lines[NR] = $0;
    if (NR > skip) print lines[NR-skip];
    delete lines[NR-skip];
}'

大きなファイルから最後の数行を削除する場合は、切り捨てる部分のバイトオフセットを特定してから、で切り捨てを実行できますdd

total=$(wc -c < /file/to/truncate)
chop=$(tail -n 42 /file/to/truncate | wc -c)
dd if=/dev/null of=/file/to/truncate seek=1 bs="$((total-chop))"

ファイルの先頭を切り捨てることはできませんが、巨大なファイルの最初の数行を削除する必要がある場合は、コンテンツ移動できます。


一部のシステム(最新のLinuxなど)では、ファイルを最初の場所で切り詰める(折りたたむ)ことができますが、通常はFSブロックサイズの倍数だけです(したがって、この場合はあまり役に立ちません)。
ステファンシャゼル

3

tail(GNU manページtailで、):

-n, --lines=K
   output the last K lines, instead of the last 10; or use -n +K to
   output lines starting with the Kth

したがって、次はsomefile.txttoの最初の2行を除くすべてを追加する必要がありますanotherfile.txt

tail --lines=+3 somefile.txt >> anotherfile.txt

3

最初のn行を削除するには、GNU sedを使用できます。たとえば、n = 2の場合

sed -n '1,2!p' input-file

!平均値は「この間隔を除外する」。あなたが想像できるように、例えば、より複雑な結果を得ることができます

sed -n '3,5p;7p'

行3、4、5、7が表示されます。アドレスの代わりに正規表現を使用することで、より強力になります。

制限は、行番号が事前にわかっている必要があることです。


1
どうしてsed 1,2d?通常は、シンプルな方が優れています。また、GNU Sedに固有の例はありません。コマンドはすべてSedの標準POSIX機能を使用します。
ワイルドカード

1

あなたは使用することができますdiffの出力を比較するためにhead/をtail元のファイルにしてから、同じであるものを削除し、そのための逆を得ます。

diff --unchanged-group-format='' foo.txt <(head -2 foo.txt)

1

一方でtail -n +4出力する第4ライン(すべてが、最初の3行)で始まるファイルは、標準およびポータブルで、そのheadカウンターパート(head -n -3、すべてが、最後の3行は)ないです。

移植性のある、あなたがするだろう:

sed '$d' | sed '$d' | sed '$d'

または:

sed -ne :1 -e '1,3{N;b1' -e '}' -e 'P;N;D'

(一部のシステムでsedは、サイズが制限されているパターンスペースがあり、大きな値にスケーリングされないことに注意してくださいn)。

または:

awk 'NR>3 {print l[NR%3]}; {l[NR%3]=$0}'

1
{   head -n2 >/dev/null
    cat  >> other_document
}   <infile

場合は<infile定期的に、あるlseek()-ableファイルは、[はい、すべての手段によって、お気軽に。上記は、POSIXで完全にサポートされている構成です。


0

私のアプローチはGillesに似ていますが、代わりにcatでファイルを反転し、headコマンドでパイプします。

tac -r thefile.txt | head thisfile.txt(ファイルを置き換えます)


0

私はあなたの必要性を明確に理解したいと思います。

リクエストを完了する方法はいくつかあります。

tail -n$(expr $(cat /etc/passwd|wc -l) - 2) /etc/passwd

どこで/ etc / passwdファイルは、あなたのファイルです

2番目の解決策は、巨大なファイルがある場合に便利です。

my1stline=$(head -n1 /etc/passwd)
my2ndline=$(head -n2 /etc/passwd|grep -v "$my1stline")
cat /etc/passwd |grep -Ev "$my1stline|$my2ndline"

0

BSDのソリューション(macOS):

最初の2行を削除します。

tail -n $( echo "$(cat foo.txt | wc -l)-2" | bc )

最後の2行を削除します。

head -n $( echo "$(cat foo.txt | wc -l)-2" | bc )

...非常にエレガントではありませんが、仕事は完了です!

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