find の -prune の使い方

find で特定ディレクトリだけ除外するために -prune を使うとたまに思い通りにいかないので調べてみた。要するに暗黙に付けられる -print によって挙動が変わる。

find . -name ".git" -prune -o -type f -print の擬似コード

find(dir)
{
  for name in dir
  {
    FollowSubDirectory = true;

    if (name == ".git") // -name ".git"
    {
      FollowSubDirectory = false; // -prune
    }
    else // -o
    {
      if (type(name) == FILE) // -type f
      {
        print name; // -print
      }
    }

    if (type(name) == DIRECTORY && FollowSubDirectory == true)
    {
      find(dir);
    }
  }
}

find . -name ".git" -prune -o -type f の疑似コード

find(dir)
{
  for name in dir
  {
    FollowSubDirectory = true;

    if (name == ".git") // -name ".git"
    {
      FollowSubDirectory = false; // -prune
      print name; // ★
    }
    else // -o
    {
      if (type(name) == FILE) // -type f
      {
        print name; // ★
      }
    }
    
    if (type(name) == DIRECTORY && FollowSubDirectory == true)
    {
      find(dir);
    }
  }
}

まとめ

アクションを一つも指定していない場合は、各条件成立時に print が指定されているものとして取り扱われる (man 参照)。これは、

アクションを指定しているときと、していないとききで find は挙動が違う場合がある

ことを意味し、

-exec で実行する前に、-exec なしで find を実行して対象を確認していたがこれは -exec が付いた場合の対象とは異なる場合がある。-print を明示的に付けるか、-exec echo '{}' などとしてきちんと評価した方がよい