[過去記事転記] Linuxでファイルを検索する: findコマンド

Linux
作者

Ryo Nakagami

公開

2023-01-01

更新日

2026-04-27

複数パターンのファイルを一括削除する

ノートコマンド

index.quarto_ipynb および index.quarto_ipynb_*_1, _2, …)に マッチする通常ファイルを,カレントディレクトリ以下から再帰的に検索し,まとめて削除する.

find . -type f \( -name "index.quarto_ipynb" -o -name "index.quarto_ipynb_*" \) -delete

各オプションの意味

要素 役割
. 検索の起点となるディレクトリ.カレントディレクトリ以下を再帰的に走査する
-type f 検索対象を 通常ファイル に限定.ディレクトリやシンボリックリンクは除外される
\( ... \) 条件のグルーピング.シェルに括弧として解釈されないようにバックスラッシュでエスケープしている
-name "..." ファイル名(パスではなく basename)に対するglobパターンマッチ.* などのワイルドカードを使う場合はクォートで囲み,シェル展開を防ぐこと
-o OR 条件.デフォルトの結合は AND(暗黙の -a)なので,「いずれかにマッチ」を表現するには明示的に -o を使う
-delete マッチしたファイルを その場で削除 するアクション.-exec rm {} \; よりも高速で安全(プロセスを起動しない)

評価順序の注意点

find-a(AND)が -o(OR)よりも優先順位が高いため,括弧でグループ化しないと意図しない条件評価になります.

## NG: -type f は最初の -name にしか効かず,2つ目の条件は -type f の制約を受けない
find . -type f -name "index.quarto_ipynb" -o -name "index.quarto_ipynb_*" -delete

## OK: 括弧で OR 条件を1つの式にまとめてから -type f, -delete を適用する
find . -type f \( -name "index.quarto_ipynb" -o -name "index.quarto_ipynb_*" \) -delete

論理式として読み下すと,前者は

\[ (\texttt{-type f} \wedge \texttt{-name A}) \vee (\texttt{-name B} \wedge \texttt{-delete}) \]

となり,-delete が条件Bにマッチした すべてのファイル(ディレクトリ含む)に対して発動してしまう危険性があります.

-delete を使うときの作法

## Step 1: 対象を確認
find . -type f \( -name "index.quarto_ipynb" -o -name "index.quarto_ipynb_*" \) -print | wc -l

## Step 2: 問題なければ削除
find . -type f \( -name "index.quarto_ipynb" -o -name "index.quarto_ipynb_*" \) -delete

例 1 xargs rm で削除するパターン

-delete が使えない環境(古い find 実装)や,削除前にファイル一覧をパイプで他コマンドに渡したいときは xargs rm のパターンが使われます.

## NG: スペースや改行を含むファイル名で壊れる
find . -type f \( -name "index.quarto_ipynb" -o -name "index.quarto_ipynb_*" \) | xargs rm

## OK: NUL区切りで安全に渡す
find . -type f \( -name "index.quarto_ipynb" -o -name "index.quarto_ipynb_*" \) -print0 | xargs -0 rm
オプション 役割
-print0 find 側の出力区切りを 改行 (\n) ではなく NUL文字 (\0) にする.ファイル名にスペース・改行・引用符が含まれていても安全
xargs -0 xargs 側の入力区切りを NUL文字として扱う.-print0 とセットで使う
xargs -r 入力が空のときコマンドを実行しない(GNU拡張).マッチが0件のときに rm がエラーになるのを防ぐ
xargs -n N 1回の rm 呼び出しに渡す引数の数を制限.デフォルトでは可能な限りまとめて渡される

-delete vs xargs rm の使い分け

観点 -delete xargs rm
プロセス起動 find 内部で完結 rm を別プロセスとして起動
実行速度 速い やや遅い(ただし xargs が引数をまとめるので -exec rm {} \; よりは速い)
ファイル名の安全性 安全 -print0 + -0 でない場合,スペース・改行で破綻する
削除前のフィルタリング 不可 可能(grep などを挟める)
移植性 POSIX外(GNU/BSD find で利用可) POSIX準拠(-print0/-0 はGNU/BSD拡張)

シンプルに削除したいだけなら -delete で十分.grep でさらに絞り込みたい,削除前後にログを取りたい,など パイプライン処理が必要な場合は xargs rm を選ぶ,という整理になります.

## 例: ファイル名に特定文字列を含むものだけを削除
find . -type f \( -name "index.quarto_ipynb" -o -name "index.quarto_ipynb_*" \) -print0 \
  | grep -z '2025-' \
  | xargs -0 -r rm

複数パターンのファイルを一括削除する with regex

ノート正規表現を用いた検索

index.quarto_ipynb および index.quarto_ipynb_1index.quarto_ipynb_2 のような連番付きファイルを, 正規表現 1 本でまとめて検索する.

find . -type f -regex '.*/index\.quarto_ipynb.*$'

各オプションの意味

要素 役割
-regex PATTERN パス全体 (basename ではなく find の起点からの相対パス全体)PATTERN完全一致するファイルを抽出
.*/ 任意の深さのディレクトリ階層に対応する先頭部分.-regex はパス全体マッチなので,これが無いと ./index.quarto_ipynb のような直下のファイルにしかマッチしない
index\.quarto_ipynb リテラルの index.quarto_ipynb. は正規表現のメタ文字なのでバックスラッシュでエスケープする
.*$ 末尾に任意文字列 (_1, _copy など) が続いてもマッチさせるための部分.完全一致セマンティクスを満たすためにアンカーまで書ききる
警告
  • -regex-name と違ってパス全体への完全一致 (= 暗黙に ^$ で囲まれる) として動作する.
    • -regex 'index\.quarto_ipynb' だけでは絶対にマッチしない (パスが ./... で始まるため).
  • . をエスケープし忘れて index.quarto_ipynb と書くと,indexAquarto_ipynb のような別名にも誤マッチする.
  • -regex のデフォルト方言は GNU find では emacs (BRE 相当) で,+?|{m,n} はそのままでは使えない.拡張正規表現を使いたいときは -regextype posix-extended を明示する.

正規表現の方言を切り替える

GNU find-regextype でバックエンドの正規表現エンジンを選べる.代表的なのは次の 3 つ:

## デフォルト (emacs / BRE 相当): + や | はリテラル扱い
find . -regextype emacs        -regex '.*/index\.quarto_ipynb.*$'

## POSIX 拡張正規表現: +, ?, |, {m,n} がメタ文字として効く
find . -regextype posix-extended -regex '.*/index\.quarto_ipynb(_[0-9]+)?$'

## POSIX 基本正規表現: + や ? はエスケープしないとリテラル
find . -regextype posix-basic   -regex '.*/index\.quarto_ipynb.*$'

-regextype最初の -regex / -iregex より前に置く必要がある (パース時に方言が確定するため).

-regex vs -name の使い分け

観点 -name (glob) -regex (正規表現)
マッチ対象 basename (ファイル名のみ) パス全体 (起点からの相対パス)
マッチ方式 glob パターン (*, ?, [...]) 正規表現 (方言は -regextype で指定)
完全一致 / 部分一致 basename への完全一致 パス全体への完全一致 (= 暗黙の ^...$)
OR 条件 \( -name A -o -name B \) で表現 (A|B)posix-extended で 1 本にまとめられる
大文字小文字を無視 -iname -iregex
直感性 高い (シェルと同じ感覚で書ける) 低め (パス先頭の .*/ を忘れやすい)

ファイル名だけで判別できるケースは -name を選んだほうがシンプル.ディレクトリ階層も条件に入れたい (例: posts/2025-*/index.quarto_ipynb 系のみ削除) ときに -regex の真価が出る.

例 2 安全な削除手順

-regex 版でも作法は -name 版と同じ.まずマッチ対象を必ず目視確認してから -delete する.

## Step 1: マッチするパスを確認
find . -type f -regex '.*/index\.quarto_ipynb.*$' -print

## Step 2: 件数を数える
find . -type f -regex '.*/index\.quarto_ipynb.*$' -print | wc -l

## Step 3: 問題なければ削除
find . -type f -regex '.*/index\.quarto_ipynb.*$' -delete

-exec でマッチしたファイルにコマンドを適用する

ノートコマンド

ディレクトリ以下にある通常ファイルすべてに実行権限を付与する.

## \; 版: ファイルごとに chmod を 1 回ずつ実行
find ~/shellutils/bin -type f -exec chmod +x {} \;

## + 版: ファイルをまとめて chmod に渡す(通常はこちら推奨)
find ~/shellutils/bin -type f -exec chmod +x {} +

\;+ の違い

-exec command {} \;-exec command {} + はどちらも「マッチしたファイルに対してコマンドを実行する」アクションだが,コマンドの起動回数が異なる.

終端子 動作 プロセス起動回数 用途
\; マッチしたファイル 1 件ごと にコマンドを 1 回実行する マッチ件数と同じ 終了コードをファイルごとに確認したい,コマンド側が複数引数に非対応など
+ マッチしたファイルをできるだけまとめて 1 コマンドに渡す(xargs 相当) はるかに少ない(コマンドライン長の上限まで引数を積む) 速度優先・chmod/chown など複数引数対応コマンド

+ 版は xargs と同じ方式でコマンドラインを構築するため,\; 版より大幅に高速になる.ただし {} は引数リストの末尾に 1 か所だけ置けるという制約がある(GNU find の仕様).

警告Warning
  • \;\ はシェルに ; を解釈させないためのエスケープ.
  • + 版では {} の直後に + を置く必要があり,{}+ のようにスペースを省略することは できない

{}(プレースホルダ)の意味

{}find がマッチしたパスに置き換える特殊文字列(プレースホルダ). \; 版では引数の任意の位置に複数回書けますが,+ 版では末尾に 1 か所だけという制約があります.

## \; 版: {} を複数回使ってよい
find . -type f -exec echo "Found: {} → processing {}" \;

## + 版: {} は末尾に 1 か所だけ(複数書くとエラー)
find . -type f -exec chmod +x {} +

条件を追加して対象を絞り込む

「拡張子 .sh だけ」「まだ実行権限がついていないファイルだけ」のように対象を絞るには,-name-perm を組み合わせる.

## 拡張子 .sh のファイルだけ
find ~/shellutils/bin -type f -name "*.sh" -exec chmod +x {} +

## 実行権限(u+x)がまだないファイルだけ
## -perm /0111  → u/g/o のいずれかに実行ビットが立っている
## ! -perm /0111 → いずれにも実行ビットがない(= 対象外 の否定 = 対象)
find ~/shellutils/bin -type f ! -perm /0111 -exec chmod +x {} +

## 拡張子 .sh かつ実行権限なし
find ~/shellutils/bin -type f -name "*.sh" ! -perm /0111 -exec chmod +x {} +

-perm の書き方

書き方 意味
-perm mode パーミッションビットが 完全一致 する
-perm -mode 指定したビットが すべて セットされている(AND マスク)
-perm /mode 指定したビットの いずれか がセットされている(OR マスク)
! -perm /mode 指定したビットが 1 つもセットされていない(NOT + OR マスク)

-perm /0111 は「u・g・o のいずれかに実行ビットが立っている」という意味で, ! -perm /0111 はその否定(= 誰にも実行権限がない)となる.

例 3 実行前の確認手順

-exec chmod は取り消しが難しいため,まず -print で対象ファイルを目視確認してから実行するのが安全です.

## Step 1: 対象を確認
find ~/shellutils/bin -type f ! -perm /0111 -print

## Step 2: 件数を数える
find ~/shellutils/bin -type f ! -perm /0111 -print | wc -l

## Step 3: 問題なければ実行
find ~/shellutils/bin -type f ! -perm /0111 -exec chmod +x {} +

-exec vs xargs の使い分け

観点 -exec {} + xargs
記述のシンプルさ 高い(find 1 本で完結) やや複雑(-print0 + xargs -0 が推奨)
ファイル名の安全性 安全(find が直接渡す) -print0 / -0 が必要
パイプでの加工 不可 grep などを挟める
プロセス起動 find 内部 xargs を別プロセスとして起動

単純にファイルに操作をかけるだけなら -exec {} + で十分. grep でさらに絞り込む,操作前後にログを取るなど,パイプライン処理が必要な場合は xargs を選ぶ.


Appendix: Linuxのファイル

Linuxで扱われるオブジェクトは大きく分けると4つあります

種類 説明 代表例 補足
通常ファイル データそのものを格納するファイル .txt, .csv, .py, バイナリ テキストも実行ファイルも同じ分類
ディレクトリ ファイルや他のディレクトリを管理するための入れ物 /home, /etc, /usr 中身は「名前 → inode」の対応表
リンクファイル 別のファイルやディレクトリへの参照 /bin -> /usr/bin ハードリンクやシンボリックリンク
特殊ファイル デバイスや IPC(入出力・通信)をファイルとして抽象化したもの(デバイスファイル) /dev/sda, /dev/null ブロックデバイス(b) や キャラクタデバイス(c)など

Linuxでは,すべてをファイルで表します.コンピューターに接続されているデバイス(キーボード・モニタ・プリンタなど)は それぞれ対応したデバイスファイルで表されます.

ls コマンドを ls -F --color=auto のように設定した上で実行すると

  • 通常ファイル: 白色
  • ディレクトリ: 青色
  • リンクファイル(シンボリックリンク): 水色
  • 特殊ファイル: 黄色

というように表示されます.(他にも圧縮ファイルは赤色,実行ファイルは緑色など)

Windowsとの差違

Windowsでは,.txt.exe といった拡張子が意味を持ち,アプリケーションと関連付けられていますが,Linuxではファイル名の一部に過ぎないです. Linuxではあくまで中身を見てから判断するという思想で,なにかしらの実行ファイルがどの言語で実行可能なのか?とかはshebang

#!/bin/bash

で記述する場面のほうが多いと思います.ただし,拡張子はどんな種類のファイルなのかの目安になるほか,

ls -X

のように ls コマンドでは -X を付与することで拡張子アルファベット順でファイルをソート表示できるので,ディレクトリの整理整頓という観点では 拡張子を含めファイルに適切な名前を付与することはLinuxでも重要です.

References