unix-ファイルの先頭と末尾


131

あなたがtxtファイルを持っているとしましょう、ファイルの上位10行と下位10行を同時に表示するコマンドは何ですか?

つまり、ファイルの長さが200行の場合は、1行目から10行目と190〜200行目を一度に表示します。


「一度に」とはどういう意味ですか?
cnicutar

@cnicutar ie。先頭-10ファイルではなくデータ見てから、末尾-10ファイルでデータを個別に見ていない
toop

あなたが本当の作業例をしたい場合は@toop、参照stackoverflow.com/a/44849814/99834
ソリン

回答:


208

あなたは簡単にできます:

(head; tail) < file.txt

そして、何らかの理由でパイプを使用する必要がある場合は、次のようにします。

cat file.txt | (head; tail)

注:file.txtの行数が先頭のデフォルトの行+末尾のデフォルトの行よりも小さい場合、重複した行が印刷されます。


54
厳密に言えば、これは元のファイルの末尾を提供しませんが、ファイルheadの最初の10行を消費した後のストリームの末尾は提供します。(これをhead < file.txt; tail < file.txt20行未満のファイルと比較してください)。覚えておくべき非常にマイナーなポイント。(ただし、+ 1のままです)
chepner 2012年

15
いいね。ヘッドパーツとテールパーツの間にギャップが必要な場合:(head; echo; tail)<file.txt
Simon Hibbs

3
これがなぜ/どのように機能するのか興味があります。新しい質問としてそれを尋ねました:stackoverflow.com/questions/13718242
zellyn

9
@nametal実際には、あなたはそれほど多くを得ることができないかもしれません。一方でheadのみ表示され、入力の最初の10行は、全くそれがなかったことが保証されていない消費少ない入力のために残して、終わる10行を見つけるために、よりそれをless表示します。
chepner 2016

20
申し訳ありませんが、答えは一部の場合にのみ機能します。seq 100 | (head; tail)最初の10個の数字だけを与えます。はるかに大きな入力サイズ(のようなseq 2000)でのみ、尾は何らかの入力を受け取ります。
モジュール式

18

ed それは standard text editor

$ echo -e '1+10,$-10d\n%p' | ed -s file.txt

2
ファイルの行数が200行より多い場合、または少ない場合はどうなりますか?そして、あなたはab initioの行数を知りませんか?
ポール

@Paul私は次のように変更sedしましたed
kev

14

純粋なストリーム(コマンドからの出力など)の場合、 'tee'を使用してストリームをフォークし、1つのストリームを先頭に、もう1つを末尾に送信できます。これには、bashの「>(list)」機能(+ / dev / fd / N)を使用する必要があります。

( COMMAND | tee /dev/fd/3 | head ) 3> >( tail )

または/ dev / fd / N(または/ dev / stderr)とサブシェルを使用して複雑なリダイレクトを行う:

( ( seq 1 100 | tee /dev/fd/2 | head 1>&3 ) 2>&1 | tail ) 3>&1
( ( seq 1 100 | tee /dev/stderr | head 1>&3 ) 2>&1 | tail ) 3>&1

(これらはどちらもcshまたはtcshでは機能しません。)

もう少し良い制御を行うには、次のperlコマンドを使用できます。

COMMAND | perl -e 'my $size = 10; my @buf = (); while (<>) { print if $. <= $size; push(@buf, $_); if ( @buf > $size ) { shift(@buf); } } print "------\n"; print @buf;'

1
ストリームサポートの場合は+1。stderrを再利用できます:COMMAND | { tee >(head >&2) | tail; } |& other_commands
jfs

2
ところで、それはバッファサイズ(私のシステムでは8K)より大きいファイルで壊れます。cat >/dev/null修正:COMMAND | { tee >(head >&2; cat >/dev/null) | tail; } |& other_commands
jfs

私は解決策を愛していましたが、aaをプレイした後、場合によってはテールがヘッドの前に走っていることに気づきました... コマンドheadtailコマンドの間の順序付けは保証されていません:\ ...
Jan

7
(sed -u 10q; echo ...; tail) < file.txt

(head;tail)テーマのもう1つのバリエーションですが、小さなファイルの最初のバッファフィルの問題を回避します。


4

head -10 file.txt; tail -10 file.txt

それ以外に、独自のプログラム/スクリプトを作成する必要があります。


1
いいですね、私はいつも使用catheadたりtailパイプしたりしてきました。それらを個別に使用できることを知って嬉しいです!
ポール、

次に、これらの最初の10+最後の10を別のコマンドにパイプする方法を教えてください。
11

1
@Paul-'your_program'がwc -lの場合、20ではなく10を返します
11:13にtoop

3
または、サブシェルを生成する{ head file; tail file; } | prog必要はあり
ません:(

1
うわー...ほぼ2年後に、他の人と非常によく似た回答(まだタイムスタンプは付けられていません)に対する反対票を投じました。いいね!
mah

4

JFセバスチャンのコメントに基づく:

cat file | { tee >(head >&3; cat >/dev/null) | tail; } 3>&1

このように、1つのパイプで最初の行と残りの行を別々に処理できます。これは、CSVデータの操作に役立ちます。

{ echo N; seq 3;} | { tee >(head -n1 | sed 's/$/*2/' >&3; cat >/dev/null) | tail -n+2 | awk '{print $1*2}'; } 3>&1
N * 2
2
4
6

3

ここでの問題は、ストリーム指向のプログラムがファイルの長さを事前に知らないことです(実際のストリームの場合、ファイルの長さが存在しない可能性があるため)。

tail最後に見たn行をバッファリングし、ストリームの終わりを待ってから印刷するようなツール。

これを単一のコマンドで実行したい場合(およびオフセットを使用して動作させ、重複している場合は行を繰り返さないようにする場合)、前述のこの動作をエミュレートする必要があります。

このawkを試してください:

awk -v offset=10 '{ if (NR <= offset) print; else { a[NR] = $0; delete a[NR-offset] } } END { for (i=NR-offset+1; i<=NR; i++) print a[i] }' yourfile

オフセットがファイルより大きい場合の問題を回避するには、さらに作業が必要です
Samus_

イェーイ、パイプで連結された出力を持つこの作品は、単なるファイルではない: a.out | awk -v ...
カミーユGoudeseune

確かに:)ですが、これはawkの通常の動作です。ほとんどのコマンドラインプログラムは、引数なしで呼び出されたときにstdinで動作します。
Samus_ 2013

1
望ましい動作に非常に近いですが、10行未満の場合、新しい行が追加されるようです。
ソリン2017年

3

このソリューションで終わるまでにはかなりの時間がかかりましたが、これはすべてのユースケース(これまでのところ)をカバーした唯一のソリューションと思われます。

command | tee full.log | stdbuf -i0 -o0 -e0 awk -v offset=${MAX_LINES:-200} \
          '{
               if (NR <= offset) print;
               else {
                   a[NR] = $0;
                   delete a[NR-offset];
                   printf "." > "/dev/stderr"
                   }
           }
           END {
             print "" > "/dev/stderr";
             for(i=NR-offset+1 > offset ? NR-offset+1: offset+1 ;i<=NR;i++)
             { print a[i]}
           }'

機能リスト:

  • ヘッドのライブ出力(明らかにテールの出力は不可能です)
  • 外部ファイルを使用しない
  • プログレスバーは、MAX_LINESの後の各行に1つのドットを持ち、長時間実行するタスクに非常に役立ちます。
  • stderrのプログレスバー。プログレスドットがヘッド+テールから分離されていることを保証します(stdoutをパイプしたい場合に非常に便利です)
  • バッファリング(stdbuf)が原因で発生する可能性のある誤ったロギング順序を回避
  • 行の総数が頭+尾よりも少ない場合は、出力の重複を避けてください。

2

私はこの解決策をしばらく探していました。sedを使って自分で試してみましたが、ファイル/ストリームの長さが事前にわからないという問題は解決できませんでした。上記で利用可能なすべてのオプションの中で、私はCamille Goudeseuneのawkソリューションが好きです。彼の解決策では、出力に十分に小さいデータセットを含む余分な空白行が残っていることに注意しました。ここでは、余分な行を削除する彼のソリューションの変更を提供します。

headtail() { awk -v offset="$1" '{ if (NR <= offset) print; else { a[NR] = $0; delete a[NR-offset] } } END { a_count=0; for (i in a) {a_count++}; for (i=NR-a_count+1; i<=NR; i++) print a[i] }' ; }

1

まあ、あなたはいつでもそれらを一緒にチェーンすることができます。のように head fiename_foo && tail filename_foo。それでも不十分な場合は、.profileファイルまたは使用するログインファイルにbash関数を記述できます。

head_and_tail() {
    head $1 && tail $1
}

そして、後でシェルプロンプトから呼び出しますhead_and_tail filename_foo


1

file.extの最初の10行、次に最後の10行:

cat file.ext | head -10 && cat file.ext | tail -10

ファイルの最後の10行、次に最初の10行:

cat file.ext | tail -10 && cat file.ext | head -10

次に、出力を他の場所にパイプすることもできます。

(cat file.ext | head -10 && cat file.ext | tail -10 ) | your_program


5
ヘッド-10 file.txtを呼び出すことができるのに、なぜ猫を使うのですか?
jstarek

行数を可変にできるので、呼び出しは次のようになります:head_tail(foo、m、n)-最初のm snd最後のn行のテキストを返しますか?
リカルド2012

@ricardoは、3つの引数を取り、それらに別名を付けることによってtailheadまたは関数に渡すbashスクリプトの記述を伴います。
ポール


1

上記のアイデアを使用して(テスト済みのbashとzsh)

しかし、別名「帽子」の頭と尾を使用する

alias hat='(head -5 && echo "^^^------vvv" && tail -5) < '


hat large.sql

0

sedこのタスクに使用しないのはなぜですか?

sed -n -e 1,+9p -e 190,+9p textfile.txt


3
これは、既知の長さのファイルには機能しますが、長さが不明なファイルには機能しません。
ケビン

0

パイプ(ストリーム)とファイルを処理するには、これを.bashrcまたは.profileファイルに追加します。

headtail() { awk -v offset="$1" '{ if (NR <= offset) print; else { a[NR] = $0; delete a[NR-offset] } } END { for (i=NR-offset+1; i<=NR; i++) print a[i] }' ; }

その後、あなたはできません

headtail 10 < file.txt

だけでなく

a.out | headtail 10

(これは、普通のとは異なり、10が入力の長さを超えた場合でも偽の空白行を追加しますa.out | (head; tail)。以前の回答者に感謝します。)

注:headtail 10ではありませんheadtail -10


0

@Aleksandra Zalcmanのコマンドがどのように機能するかについて@Samus_がここで説明したことに基づいて、このバリエーションは、線を数えずに尾がどこから始まるのかをすぐに見つけることができない場合に便利です。

{ head; echo "####################\n...\n####################"; tail; } < file.txt

または、20行以外で作業を開始する場合は、行数が役立つ場合もあります。

{ head -n 18; tail -n 14; } < file.txt | cat -n

0

ファイルの最初の10行と最後の10行を印刷するには、次のようにします。

cat <(head -n10 file.txt) <(tail -n10 file.txt) | less


0
sed -n "1,10p; $(( $(wc -l ${aFile} | grep -oE "^[[:digit:]]+")-9 )),\$p" "${aFile}"

aFile変数には、ファイルの完全パスが含まれています。


0

ファイルのサイズによっては、その内容を積極的に読み込むことが望ましくない場合があります。そのような状況では、単純なシェルスクリプトで十分です。

これが、私が分析していた非常に大きなCSVファイルの数について、私が最近これをどのように処理したかです。

$ for file in *.csv; do echo "### ${file}" && head ${file} && echo ... && tail ${file} && echo; done

これにより、各ファイルの最初の10行と最後の10行が出力され、その前後にファイル名と省略記号も出力されます。

単一の大きなファイルの場合、次のコマンドを実行するだけで同じ効果が得られます。

$ head somefile.csv && echo ... && tail somefile.csv

0

stdinを使用しますが、シンプルで、ユースケースの99%で機能します

head_and_tail

#!/usr/bin/env bash
COUNT=${1:-10}
IT=$(cat /dev/stdin)
echo "$IT" | head -n$COUNT
echo "..."
echo "$IT" | tail -n$COUNT

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