headとtailは、それぞれファイルの先頭・末尾から指定した行数だけを表示するコマンドです。巨大なログファイルの中身を全部表示すると画面が流れてしまいますが、headやtailなら「最初だけ」「最後だけ」をさっと確認できます。とくにtail -fは、ログファイルへの追記をリアルタイムに監視できる、運用作業で欠かせない機能です。
この記事では、実機のLinux(WSLのDebian)でhead・tailの基本を確認したあと、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行が表示されます。
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行が正しく取得でき、オプションを付けないhead/tailは既定で10行を表示することを確認しました。ログファイルの冒頭(起動時の設定ログなど)を見るならhead、直近のエラーを見るならtailと使い分けます。複数のファイルを一度に指定すると、==> ファイル名 <==という見出し付きでそれぞれの内容が表示されます。
【最重要】tail -fでログをリアルタイム監視する
tailの真骨頂が-f(follow)です。ファイルの末尾を表示したあとコマンドを終了せず、新しく追記された行をそのまま画面に流し続けます。アプリケーションのログを見ながらの動作確認で必須の機能です。
# ログファイルの末尾を表示したまま、追記を監視し続ける tail -f app.log # ↑ 新しい行が書き込まれるたびに、リアルタイムで表示される # 終了するには Ctrl+C # よく使う組み合わせ: 直近100行を表示してから監視開始 tail -n 100 -f app.log
実機で、tail -fをバックグラウンドで起動したあとから、1秒おきに3行をファイルへ追記したところ、tail -fの出力には起動前からあった行に加えて、起動後に書き込んだ3行すべてが正しく表示されました。tail -fは、ファイルの末尾位置を監視し続け、新しいバイトが追記されるたびにそれをそのまま画面へ流す仕組みです。Webサーバーやアプリケーションのログファイルを見ながら「今何が起きているか」をリアルタイムに確認したいときの定番コマンドで、tail -f /var/log/nginx/access.logのような使い方が典型例です。
【重要】ログローテーションでは-fが追従できない罠
tail -fには、意外と知られていない弱点があります。ログローテーション(元のファイルが新しいファイルに置き換わる処理)が起きると、-fは新しいファイルを追えなくなります。
# tail -f で監視を開始 tail -f app.log & # ログローテーションで元のファイルを退避し、新しいファイルを作る mv app.log app.log.old echo "new log content" > app.log # tail -f はまだ「古いファイルの実体」を見ているため、 # 新しい app.log に書かれた内容は表示されない
実機で、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(大文字)ならローテーション後も追従できる 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行を除いた全部」という、少し特殊な指定です。
# 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 +18で18行目から末尾まで、head -n -17で末尾17行を除いた先頭部分が正しく取得できました。tail -n +2でCSVの1行目(ヘッダー行)を飛ばして本体だけ処理するのは、awkと並んでCSV処理でよく使われるテクニックです。+と-で意味が逆になる(+Nは「N行目から」、-Nは「末尾N行を除く」)ため、最初は混同しやすい点に注意してください。
主な書き方一覧
head・tailでよく使う書き方をまとめます。
| 書き方 | 働き |
|---|---|
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する
画面が流れて読めません。まずheadやtailで概要を確認します。
tail -fを終了し忘れてターミナルが専有される
Ctrl+Cで終了できます。バックグラウンドで動かした場合はプロセスの終了を忘れないようにします。
CSVのヘッダー行を含めたまま処理してしまう
tail -n +2で1行目(ヘッダー)を除いた本体だけを取り出せます。
よくある質問
tail -f ファイル名を使います。ファイルの末尾を表示したあと、新しく追記された内容をそのまま画面に流し続けます。実機でも、起動後に追記した内容がすべて正しく表示されることを確認しています。終了はCtrl+Cです。tail -fは開いた時点のファイルの実体を見続けるため、名前が変わって新しいファイルが作られると追従できません。実機でもこの現象を再現しています。-F(大文字)を使うと、新しいファイルを自動的に検知して監視を継続できます。head -n 数 ファイルで先頭N行、tail -n 数 ファイルで末尾N行を表示できます。オプションを付けない場合は、既定で10行が表示されます。tail -n +2 ファイルを使います。+2は「2行目から最後まで」を意味するため、1行目(ヘッダー行)を除いた本体部分だけを取り出せます。実機でも、この指定で正しく2行目以降が取得できることを確認しています。-f(小文字)はログローテーションでファイルが置き換わると追従できなくなります。-F(大文字)は、ファイルが一時的に消えても再び現れたら自動的に新しいファイルを開き直して監視を続けます。実機でも、-fは新ファイルの内容を表示できず、-Fは正しく検知して表示することを確認しています。まとめ
head -n 数で先頭、tail -n 数で末尾。既定は10行です。tail -fでログをリアルタイム監視できます(Ctrl+Cで終了)。- ログローテーション後は
-fだと追従できません。-F(大文字)を使います。 tail -n +Nは「N行目から」、head -n -Nは「末尾N行を除く」。
head・tailは、シンプルながら日々の運用に欠かせないコマンドです。「tail -fでリアルタイム監視、ローテーションに備えるなら-F」という一点さえ覚えておけば、ログを追いかける作業がずっと確実になります。
- grep(文字列検索)
- find(ファイル検索)
- sed(置換・行編集)
- awk(列抽出・集計)
- chmod(パーミッション)
- tar(圧縮・解凍)
- リダイレクトとパイプ
- ps・kill(プロセス管理)
- 環境変数とPATH
- ln(シンボリックリンク)
- cp・mv・rm(コピー/移動/削除)
- history(コマンド履歴)
- curl(HTTP通信・API)
- jq(JSON処理)
- vim(基本操作・終了方法)
- cron・crontab(定期実行)
- sort・uniq・wc(並べ替え/集計)
- xargs(一括処理)
- chown・chgrp(所有者/グループ変更)
- diff(ファイル比較)
- du・df(ディスク使用量)
- head・tail(先頭/末尾・ログ監視)
- よく使うコマンドまとめ
- cd(ディレクトリ移動)
