圧縮ファイルを眺めたい(zcat / zless)

$ zcat -f 圧縮ファイル.gz

$ zless 圧縮ファイル.gz
$ zmore 圧縮ファイル.gz

// macOS
$ gzcat 圧縮ファイル.gz

zcatは、gzip形式の圧縮ファイルを展開せずに中身を標準出力に表示するコマンドです。 zlessやzmoreは、展開せずに中身をページングして表示するコマンドです。

gzcatは、macOSやFreeBSDなどの一部の環境で使えるzcatです。

注意

macOSのzcatは、.Z形式の拡張子を期待するため、.gzファイルをそのまま渡すとエラーになります。 -f(--force)オプションを付けるか、gzcatを使いましょう。

注釈

zcatやzlessは、あるブロックサイズごとにストリーミングして標準出力に表示します。 そのため、zcatで大きな圧縮ファイルを展開しても、ディスク容量やメモリを圧迫することはほとんどありません。

圧縮ファイルを表示したい(zcat / gzcat)

$ zcat -f 圧縮ファイル.gz
$ gzcat 圧縮ファイル.gz

zcat(macOSではgzcat)で、圧縮ファイルの中身を展開せずにまとめて標準出力に表示できます。

圧縮ファイルをページャーしたい(zless / zmore)

$ zless 圧縮ファイル.gz
$ zmore 圧縮ファイル.gz

zlessやzmoreで、圧縮ファイルの中身を展開せずにページャーでスクロールしながら見られます。

圧縮ファイルを検索したい(zgrep / rg -z)

$ zgrep '検索パターン' 圧縮ファイル.gz
$ rg -z '検索パターン' 圧縮ファイル.gz

zgrepで、圧縮ファイルを展開せずに中身を検索できます。 複数の圧縮ファイルをまとめて指定することもできます。

Apacheログを集計したい

Apacheのアクセスログは、ログローテーションして月ごとにgzip形式で圧縮されていることが多いです。 これを毎月、展開して集計するのは手間がかかる上にディスク容量も圧迫します。 zcatでストリーミングしつつ集計するのが便利です。

// ステータスコード別に集計する(全期間まとめて)
$ zcat -f access_log.*.gz | grep -oE '" [0-9]{3} ' | tr -d '" ' | sort | uniq -c | sort -rn

// ripgrepを使う場合(-Eなしで拡張正規表現が使える)
$ zcat -f access_log.*.gz | rg -o '" [0-9]{3} ' | tr -d '" ' | sort | uniq -c | sort -rn

zcat -f access_log.*.gzで、複数の月のアクセスログをまとめて展開します。 rg -o '" [0-9]{3} 'で、ステータスコードの部分だけを抽出し、tr -d '" 'で余計な文字を削除します。 sort | uniq -c | sort -rnで、ステータスコードごとに件数を集計して降順に並べます。

*access_log.*.gzにすると、HTTPとHTTPSのログをまとめて集計できます。 *access_log.2026-*.gzにすると、2026年のログだけを集計できます。

// アクセス数の多いIP TOP10(1ファイル分)
$ zcat -f access_log.2026-08-01.gz | awk '{print $1}' | sort | uniq -c | sort -rn | head -10
// アクセスの多いURL TOP10(1ファイル分)
$ zcat -f access_log.2026-08-01.gz | awk -F'"' '{print $2}' | awk '{print $2}' | sort | uniq -c | sort -rn | head -10

// 静的アセットやbot・不正アクセス系のパスを除外して、ページとして意味のあるURLに絞る
$ zcat -f access_log.2026-08-01.gz | awk -F'"' '{print $2}' | awk '{print $2}' | \
    grep -vE '\.(js|css|png|jpe?g|gif|svg|ico|woff2?|ttf|map|xml|txt|json)($|\?)' | \
    grep -vE '^/(wp-|\.well-known|\.env|xmlrpc\.php|feed$|\?)' | \
    grep -v '^$' | \
    sort | uniq -c | sort -rn | head -10
// 404になっているURLだけ抽出する(全期間まとめて)
$ zcat -f access_log.*.gz | awk '$9 == 404 {print $7}' | sort | uniq -c | sort -rn | head -20
// 攻撃的・不審なパスへのアクセスを検出する(全期間まとめて)
$ zcat -f access_log.*.gz | awk -F'"' '{print $2}' | awk '{print $2}' | \
    grep -iE '\.(env|git|sql|bak)|wp-login|wp-admin|xmlrpc|phpmyadmin|\.\./|<script|union.*select|/etc/passwd|phpinfo' | \
    sort | uniq -c | sort -rn | head -20

// 不審なパスにアクセスしているIP TOP10
$ zcat -f access_log.*.gz | \
    grep -iE '\.(env|git|sql|bak)|wp-login|wp-admin|xmlrpc|phpmyadmin|\.\./|<script|union.*select|/etc/passwd|phpinfo' | \
    awk '{print $1}' | sort | uniq -c | sort -rn | head -10
// 月別アクセス数の推移
$ for f in access_log.2026-*.gz; do
    n=$(zcat -f "$f" | wc -l)
    echo "$f: $n"
  done

zcat -fで複数の圧縮済みログをまとめて展開しつつ、awk・grep・sortにパイプで渡して集計できます。 ステータスコードの抽出はawk '{print $9}'でも取れますが、リクエスト行やUser-Agentにスペースが含まれていると列がずれるため、"とステータスコードの並びを正規表現で狙う方が確実です。

アクセスの多いURLをそのまま集計すると、.jsや.cssなどの静的アセットや、/wp-login.phpのような脆弱性スキャン・bot系のアクセスが上位を占めてしまいがちです。 grep -vで拡張子・パスのパターンを除外していくと、実際に読まれているページに近いランキングになります。 除外パターンはサイトの構成やアクセス傾向によって変わるので、自分のログを見ながら調整するとよいです。

逆に、.envや.git/configの探索、wp-login・wp-adminへの総当たり、SQLインジェクションやパストラバーサルの試みといった攻撃的なパスだけをgrepで拾うこともできます。 アクセス元IPで集計すれば、しつこくスキャンしてくるIPを特定できます。 検出パターンは網羅的ではないので、実際のログに出てくる不審なアクセスを見ながら育てていくとよいです。