UNIX/Linuxの部屋 tailコマンドの使い方

TOP UNIX/Linuxの部屋 UNIX/Linuxコマンド一覧 用語集 新版 由来/読み方辞書 環境変数マニュアル Cシェル変数 システム設定ファイル システムコール・ライブラリ ネットワークプログラミングの基礎知識 クラウドサービス徹底比較・徹底解説




コマンド tail ファイルの最終部分を表示 (パイプ) このエントリーをはてなブックマークに追加

UNIX/Linux の tail コマンドは、ファイルの末尾 N行を表示したり、ログファイルを監視してログに追記されたものをリアルタイム表示できるコマンドである。



tail コマンドの基本的な使い方
tail コマンドは、デフォルトでは、最後の 10 行を表示する。
% tail sample.dat
⇒ sample.dat の最後の 10 行を表示する。
オプションを指定することで、最後の N 行や、N行名から最後まで、という表示の仕方もできる。
% tail -n 5 sample.dat
⇒ sample.dat の最後の 5 行を表示する。
% tail -n +5 sample.dat
⇒ sample.dat の、先頭から 5 行目以降 (5行目から最後まで) 表示する。
tail コマンドに -f オプションを使うことで、ログファイルを監視することができる。
$ tail -f /var/log/messages
⇒ ログファイル messages に追記されるたびに、追記された内容を表示する。
$ tail -f /var/log/messages | grep hogehoge
⇒ 追記された内容を特定文字列で絞る

tail コマンドのオプション
▷ -c number
最後の number バイトを表示
▷ -n number
最後の number 行を表示
▷ -r ファイルの内容を行単位で逆にする
% cat sample.dat
line1
line2
line3
% tail -r sample.dat
line3
line2
line1
GNU の tail には -r オプションが存在しない。その場合は tac (cat の逆) を使うとよい。
▷ -f ファイルを最後まで表示しても終了せず、それより後にファイルに追加された内容を表示する。
tail -f は、ログファイルを監視する際に便利である。
% tail -f /var/log/messages
のようにすると、/var/log/messages に追加された内容を順次表示する。ちなみに less コマンド起動中に "F" (大文字の f) を押下することで、tail -f と同じような挙動をする。

また。tail -f の出力から、grep コマンドで欲しい出力のみを取得するのも便利な使い方である。
% tail -f /var/log/syslog | grep hoge
なお、
% tail -f /var/log/syslog | grep hoge | grep -v fuga
のように grep を 2段に重ねた場合、最初の grep がバッファリングを行なってしまうためログに追記された内容がすぐには表示されない。そのようなときは以下のように --line-buffered オプションを使うとよい (Linux と *BSD で使用可。FreeBSD は 5.3-RELEASE 以降)。
% tail -f /var/log/syslog | grep --line-buffered hoge | grep -v fuga
▷ -F ファイル名の変更などが発生した場合、新ファイルをオープンしなおす。
詳しくは後述。

複数ファイルに対する -f オプション
Linux などで使用されている GNU tail では、下記のように複数ファイルの追加データを表示可能である (3個以上も可能)。
% tail -f file1.log file2.log
しかしながら、
==> file1.log <==
...(file1.log の追加行)...

==> file2.log <==
...(file2.log の追加行)...

==> file1.log <==
...(file1.log の追加行)...
という表示になるため、いまいち使いづらい。また、GNU tail 以外の tail コマンドでは、そもそも -f 指定時に複数ファイルを指定できない。

どの tail でも受け付けることができ、なおかつ見やすい形は、以下のようなものではないかと当ページ管理人は考えるが、どうだろうか。
% tail -f file1.log | sed 's/^/file1.log:/' & tail -f file2.log | sed 's/^/file2.log:/'
file1.log: ...(file1.log の追加行)...
file2.log: ...(file2.log の追加行)...
file1.log: ...(file1.log の追加行)...

tail コマンドの -f オプションと -F オプション
tail -f は、ファイルをオープンし続けるため、ファイル名が変更になった場合でも、ファイル名変更後の追加行を表示する。言葉で説明してもわかりづらいため、実験してみよう。
#!/bin/sh

rm -f hoge.log hoge.log.bak
touch hoge.log

tail -f hoge.log &
tail_pid=$!
sleep 1;

echo "2. hoge.log に 1行追加" >> hoge.log

mv hoge.log hoge.log.bak
sleep 1;
echo "4. hoge.log に、さらに 1行追加" >> hoge.log
sleep 1;
echo "5. hoge.log.bak に 1行追加" >> hoge.log.bak
sleep 1;

kill $tail_pid
上記シェルスクリプトは、
1. hoge.log を tail -f する。
2. hoge.log に 1行追加
3. hoge.log を hoge.log.bak にリネーム
とした後に、
4. hoge.log に、さらに 1行追加
5. hoge.log.bak に 1行追加
という処理を行うものである。

このシェルスクリプトを実行したとき tail -f が表示する内容は、
2. hoge.log に 1行追加
5. hoge.log.bak に 1行追加
である。つまり、tail -f は hoge.log から hoge.log.bak へのファイル名変更に追随しているということである。これは tail -f が特別なことをしているわけではなく、ファイルオープン中にファイル名が変更されても、オープン中のディスクリプタはリネーム前のファイルを指しているという UNIX の特性のためである。

一方、tail -F は、追加行を表示するという意味では同じであるが、ファイル名がリネームされた場合はファイルをオープンし直すという特徴がある。上記シェルスクリプトの
tail -f hoge.log &
の行を
tail -F hoge.log &
と修正して実行すると、tail -F は以下の内容を表示する。
2. hoge.log に 1行追加
4. hoge.log に、さらに 1行追加
である。つまり、tail -F は hoge.log がリネームされたことを検知し、再度 hoge.log をオープンしなおして追加行を表示し始めたわけである。

tail -F は、web サーバや syslog のように、期間やファイルサイズによりローテートされるログファイルの場合に使用すると便利である。

なお、FreeBSD の tail では上記の実験は成功するが、GNU tail だとうまくいかない。GNU tail のデフォルト動作は、5回連続でファイルサイズに変更がない場合のみファイル名が変更されたかどうかをチェックするという挙動であるためである。この場合、tail に「1回でもファイルサイズに変更がなかった場合、ファイル名変更チェックを行う」という挙動をさせるため、以下のように --max-unchanged-status オプションを指定する必要がある。
tail -F --max-unchanged-stats=1 hoge.log &

なお、-F オプションを実装した tail は、GNU tail と FreeBSD の tail のみではないかと思われる。

tailf コマンド
Linux には tailf というコマンドがある。マニュアル (JM) には
tailf は tail -f と似ているが、ファイルへの追加書き込みがないとファイルへアクセスを行わない。したがってファイルのアクセス時間は更新されないので、ログに関る動作が起らない間は、定期的なファイルシステムのフラッシュも生じない。tailf は、ラップトップで、あまり頻繁に書き込まれない状態のログファイルを監視にする場合に大変便利である。ハードディスクをスピンダウンさせ、電池を長持ちさせることができる。
と記述されているが、2006/11 現在 tail -f と tailf はいずれも以下の動作を繰り返すだけで、同じ挙動をしている。
  • stat(2) でファイルサイズをチェックし、サイズが増えていたら内容表示
  • sleep(2) で一定時間スリープする
tailf コマンドが作成されたと思われる 2003年当時は tail -f はムダの多い動作をしていたのかもしれないが、今となっては tailf コマンドを使用する理由はない。Linux 以外の OS では tailf は存在しない。

ちなみに FreeBSD では kqueue・kevent 化されており、さらに実行効率が高まっていると思われる。参照: http://X68000.q-e-d.net/~68user/net/c-kqueue-1.html

tail -f の仲間たち
less コマンドでファイルを表示中に `F' キーを押下すると、最下行が以下のような表示となり、tail -f と同じような挙動をする。Ctrl-c で通常の less のモードの戻る。
Waiting for data... (interrupt to abort)
lv コマンドも同様に、`F' キーで tail -f モード、Ctrl-c で元に戻る。
Waiting for data, break (^C) to return...

tail を使った小技
ファイルの末尾 5 行を削除して表示する。
% cat sample.dat | tail -r | tail +6 | tail -r

ファイルの 5行目から 10行目までを表示する。
% cat sample.dat | head -10 | tail -`expr 10 - 5 + 1`

ファイルの先頭 2行と末尾 5行を削除するには -r を利用する。ただし、巨大なファイルの場合はそれなりのメモリを喰うので注意 (ウソかも。mmap を使うような tail であれば、メモリは消費しないかもしれない)。
% cat sample.dat | tail +3 | tail -r | tail +6 | tail -r

出力日時が記載されていないログファイルについて、行が出力された日時を行頭に付け加える。
% tail -f logfile | perl -pe '$|=1;@x=localtime();$x=sprintf("%02d/%02d/%02d %02d:%02d:%02d: ",$x[5]+1900,$x[4]+1,$x[3],$x[2],$x[1],$x[0]); s/^/$x/;'
>> FreeBSDオンラインマニュアル(man) FreeBSD tail(1)
>> Solaris10オンラインマニュアル(man) Solaris10 tail(1)
>> Linuxオンラインマニュアル(man) Linux tail(1)