【Linux】head・tailの使い方|先頭/末尾N行の取得とtail -fでのログ監視

headtailは、それぞれファイルの先頭・末尾から指定した行数だけを表示するコマンドです。巨大なログファイルの中身を全部表示すると画面が流れてしまいますが、headtailなら「最初だけ」「最後だけ」をさっと確認できます。とくにtail -fは、ログファイルへの追記をリアルタイムに監視できる、運用作業で欠かせない機能です。

この記事では、実機のLinux(WSLのDebian)でheadtailの基本を確認したあと、tail -fが実際にファイルへの追記を追いかける様子と、ログローテーション(ファイルの置き換え)が起きると-fだけでは追従できなくなるという、実務で意外と知られていない挙動を実際に再現します。

先に結論

  • head -n 数で先頭N行、tail -n 数で末尾N行を表示します。
  • オプションを付けないと、既定は先頭・末尾の10行です。
  • tail -fで、ファイルへの追記をリアルタイムに監視できます(ログ監視の定番)。
  • tail -n +Nは「N行目から最後まで」、head -n -Nは「末尾N行を除いた全部」です。
  • ログローテーションでファイルが置き換わると、-fは追従できなくなります
  • ローテーションに対応するには-F(大文字)を使います。

ファイル全体を検索するgrep、リアルタイム監視と組み合わせるプロセス管理はps・kill、リダイレクトの基本はリダイレクトとパイプもあわせて参考になります。

スポンサーリンク

headとtailの基本:先頭N行・末尾N行

head -n 数 ファイルで先頭から指定した行数、tail -n 数 ファイルで末尾から指定した行数を表示します。オプションを付けないと、既定で10行が表示されます。

head と tail の基本
seq 1 20 > nums.txt   # 1〜20の20行のファイル

# 先頭3行
head -n 3 nums.txt
# 1
# 2
# 3

# 末尾3行
tail -n 3 nums.txt
# 18
# 19
# 20

# オプションなしは既定で10行
head nums.txt   # 1〜10行目
tail nums.txt   # 11〜20行目

実機でも、head -n 3で先頭3行、tail -n 3で末尾3行が正しく取得でき、オプションを付けないheadtailは既定で10行を表示することを確認しました。ログファイルの冒頭(起動時の設定ログなど)を見るならhead、直近のエラーを見るならtailと使い分けます。複数のファイルを一度に指定すると、==> ファイル名 <==という見出し付きでそれぞれの内容が表示されます。

【最重要】tail -fでログをリアルタイム監視する

tailの真骨頂が-f(follow)です。ファイルの末尾を表示したあとコマンドを終了せず、新しく追記された行をそのまま画面に流し続けます。アプリケーションのログを見ながらの動作確認で必須の機能です。

tail -f でリアルタイム監視
# ログファイルの末尾を表示したまま、追記を監視し続ける
tail -f app.log
#   ↑ 新しい行が書き込まれるたびに、リアルタイムで表示される
#     終了するには Ctrl+C

# よく使う組み合わせ: 直近100行を表示してから監視開始
tail -n 100 -f app.log
実際に追記しながらtail -fの追従を確認(実証)

実機で、tail -fをバックグラウンドで起動したあとから、1秒おきに3行をファイルへ追記したところ、tail -fの出力には起動前からあった行に加えて、起動後に書き込んだ3行すべてが正しく表示されました。tail -fは、ファイルの末尾位置を監視し続け、新しいバイトが追記されるたびにそれをそのまま画面へ流す仕組みです。Webサーバーやアプリケーションのログファイルを見ながら「今何が起きているか」をリアルタイムに確認したいときの定番コマンドで、tail -f /var/log/nginx/access.logのような使い方が典型例です。

【重要】ログローテーションでは-fが追従できない罠

tail -fには、意外と知られていない弱点があります。ログローテーション(元のファイルが新しいファイルに置き換わる処理)が起きると、-fは新しいファイルを追えなくなります

-f はファイルの置き換えに追従できない
# tail -f で監視を開始
tail -f app.log &

# ログローテーションで元のファイルを退避し、新しいファイルを作る
mv app.log app.log.old
echo "new log content" > app.log

# tail -f はまだ「古いファイルの実体」を見ているため、
# 新しい app.log に書かれた内容は表示されない
-fはローテーション後の新ファイルを追えない(実証)

実機で、tail -f app.logを起動した状態でmv app.log app.log.oldとしてファイル名を変え、新しくapp.logを作り直したところ、tail -fの出力には「新しいファイルに書いた内容」がまったく表示されませんでした。これはtail -fファイル名ではなく、開いた時点のファイルの実体(inode)を監視し続けているためです。mvで名前が変わっても、tail -fは古い実体(今はapp.log.oldという名前になった側)を見続けており、新しく作られたapp.logとは無関係になってしまいます。logrotateなどのログローテーション運用では、この現象に必ず出会います

この問題を解決するのが-F(大文字)です。-F-fに加えて「ファイル名が消えて再び現れたら、新しいファイルを開き直す」機能を持っています。

-F はローテーション後も追従する
# -F(大文字)ならローテーション後も追従できる
tail -F app.log &

mv app.log app.log.old
echo "new log content" > app.log

# tail: 'app.log' has become inaccessible: No such file or directory
# tail: 'app.log' has appeared;  following new file
#   ↑ 自動的に新しいファイルを検知して監視を継続する

実機でも、-Fで監視している最中に同じ手順でローテーションを行うと、'app.log' has become inaccessible(一時的に見失う)→'app.log' has appeared; following new file(新しいファイルを検知)というメッセージのあと、新しいファイルに書いた内容が正しく表示されました。本番サーバーのログをずっと監視し続けるなら、-fではなく-Fを使うのが安全です。logrotateが動いている環境では、この違いが「気づいたら監視が止まっていた」という事故を防いでくれます。

行番号を指定した応用(+N・負数)

tail -n +N(プラス記号)は「N行目から最後まで」、head -n -N(マイナス記号)は「末尾N行を除いた全部」という、少し特殊な指定です。

+Nと-Nの応用
# tail -n +18: 18行目から最後まで(末尾から数えるのと逆)
tail -n +18 nums.txt
# 18
# 19
# 20

# head -n -17: 末尾17行を"除いた"先頭部分
head -n -17 nums.txt
# 1
# 2
# 3

# ヘッダー行(1行目)を除いた本体だけをCSVから取り出す定番技
tail -n +2 data.csv

実機でも、tail -n +1818行目から末尾までhead -n -17末尾17行を除いた先頭部分が正しく取得できました。tail -n +2でCSVの1行目(ヘッダー行)を飛ばして本体だけ処理するのは、awkと並んでCSV処理でよく使われるテクニックです。+-で意味が逆になる(+Nは「N行目から」、-Nは「末尾N行を除く」)ため、最初は混同しやすい点に注意してください。

主な書き方一覧

headtailでよく使う書き方をまとめます。

書き方 働き
head -n 数 / tail -n 数 先頭 / 末尾の指定行数
オプションなし 既定で10行
tail -f 追記をリアルタイム監視(ログ監視の定番)
tail -F ログローテーションにも追従
tail -n +N N行目から最後まで
head -n -N 末尾N行を除いた全部

よくある失敗

tail -fで監視していたのに更新が止まって見える

ログローテーションでファイルが置き換わった可能性があります。-F(大文字)を使います。

+Nと-Nの意味を混同する

tail -n +Nは「N行目から」、head -n -Nは「末尾N行を除く」です。符号の向きに注意します。

大きいファイルにheadやtailを付けずcatする

画面が流れて読めません。まずheadtailで概要を確認します。

tail -fを終了し忘れてターミナルが専有される

Ctrl+Cで終了できます。バックグラウンドで動かした場合はプロセスの終了を忘れないようにします。

CSVのヘッダー行を含めたまま処理してしまう

tail -n +2で1行目(ヘッダー)を除いた本体だけを取り出せます。

よくある質問

Qログファイルをリアルタイムで監視するには?
Atail -f ファイル名を使います。ファイルの末尾を表示したあと、新しく追記された内容をそのまま画面に流し続けます。実機でも、起動後に追記した内容がすべて正しく表示されることを確認しています。終了はCtrl+Cです。
Qtail -fで監視していたのに、ある時点から更新が表示されなくなりました。
Aログローテーション(ファイルが新しいものに置き換わる処理)が起きた可能性があります。tail -fは開いた時点のファイルの実体を見続けるため、名前が変わって新しいファイルが作られると追従できません。実機でもこの現象を再現しています。-F(大文字)を使うと、新しいファイルを自動的に検知して監視を継続できます。
Q先頭・末尾だけを何行か確認したいです。
Ahead -n 数 ファイルで先頭N行、tail -n 数 ファイルで末尾N行を表示できます。オプションを付けない場合は、既定で10行が表示されます。
QCSVのヘッダー行を除いて処理するには?
Atail -n +2 ファイルを使います。+2は「2行目から最後まで」を意味するため、1行目(ヘッダー行)を除いた本体部分だけを取り出せます。実機でも、この指定で正しく2行目以降が取得できることを確認しています。
Qtail -fとtail -Fの違いは何ですか?
Aどちらもファイルへの追記をリアルタイムに監視しますが、-f(小文字)はログローテーションでファイルが置き換わると追従できなくなります。-F(大文字)は、ファイルが一時的に消えても再び現れたら自動的に新しいファイルを開き直して監視を続けます。実機でも、-fは新ファイルの内容を表示できず、-Fは正しく検知して表示することを確認しています。

まとめ

  • head -n 数で先頭、tail -n 数で末尾。既定は10行です。
  • tail -fでログをリアルタイム監視できます(Ctrl+Cで終了)。
  • ログローテーション後は-fだと追従できません-F(大文字)を使います。
  • tail -n +Nは「N行目から」、head -n -Nは「末尾N行を除く」。

headtailは、シンプルながら日々の運用に欠かせないコマンドです。「tail -fでリアルタイム監視、ローテーションに備えるなら-F」という一点さえ覚えておけば、ログを追いかける作業がずっと確実になります。