検索結果ごとに特定のコマンドを実行するにはどうすればよいですか?


49

コマンドを使用して見つかった各ファイルに対して特定のコマンドを実行するにはどうすればよいfindですか?質問の目的のために、で見つかった各ファイルを単に削除したいと言ってみましょうfind

回答:


60

編集:次の回答では一般的な使用例を説明していますが、ファイルとディレクトリの削除は特別な場合です。-execdir rm {} \;構造を使用する代わりに、次のようにを使用-deleteします。

find -iname '*.txt' -delete

これにより、エラーが発生しないようにファイルやディレクトリを削除する必要がある順序を含めることを考えていない可能性のある多数のエッジケースが処理されます。他のユースケースの場合...

検索結果の実行中のコマンドを処理する最良の方法は、通常-execfindコマンドのさまざまなオプションを使用することです。特に-execdir、発見されたファイルのディレクトリ内で実行され、他のオプションよりも一般的に安全である(愚かな間違いを壊滅させるという意味で)ため、可能な限り使用するようにしてください。

-execオプションは、あなたが実行したいコマンドが続いている{}含まれなければならないとのいずれかによって終了されたファイルは検索で見つかった場所を示す\;ファイルごとにコマンドを1回実行するか、+交換するために{}すべてのマッチの引数のリストに。セミコロンターミネータはエスケープされているため、シェルが新しいコマンドにつながるセパレータとして認識されないことに注意してください。

すべてのテキストファイルを見つけていたとしましょう:

find -iname '*.txt' -execdir rm {} \;

以下に、検索マニュアル(man find)からの関連ビットを示します。

   -exec command ;
          Execute  command;  true  if 0 status is returned.  All following
          arguments to find are taken to be arguments to the command until
          an  argument  consisting of ‘;’ is encountered.  The string ‘{}’
          is replaced by the current file name being processed  everywhere
          it occurs in the arguments to the command, not just in arguments
          where it is alone, as in some versions of find.  Both  of  these
          constructions might need to be escaped (with a ‘\’) or quoted to
          protect them from expansion by the shell.  See the EXAMPLES sec-
          tion for examples of the use of the -exec option.  The specified
          command is run once for each matched file.  The command is  exe-
          cuted  in  the starting directory.   There are unavoidable secu-
          rity problems surrounding use of the -exec  action;  you  should
          use the -execdir option instead.


   -exec command {} +
          This  variant  of the -exec action runs the specified command on
          the selected files, but the command line is built  by  appending
          each  selected file name at the end; the total number of invoca-
          tions of the command will  be  much  less  than  the  number  of
          matched  files.   The command line is built in much the same way
          that xargs builds its command lines.  Only one instance of  ‘{}’
          is  allowed  within the command.  The command is executed in the
          starting directory.


   -execdir command ;

   -execdir command {} +
          Like -exec, but the specified command is run from the  subdirec-
          tory  containing  the  matched  file,  which is not normally the
          directory in which you started find.  This a  much  more  secure
          method  for invoking commands, as it avoids race conditions dur-
          ing resolution of the paths to the matched files.  As  with  the
          -exec action, the ‘+’ form of -execdir will build a command line
          to process more than one matched file, but any given  invocation
          of command will only list files that exist in the same subdirec-
          tory.  If you use this option, you must ensure that  your  $PATH
          environment  variable  does  not  reference  ‘.’;  otherwise, an
          attacker can run any commands they like by leaving an  appropri-
          ately-named  file in a directory in which you will run -execdir.
          The same applies to having entries in $PATH which are  empty  or
          which are not absolute directory names.

Busyboxが提供する「find」コマンドは-execdirオプションをサポートしていないため、以下で説明するpipe / xargsメソッドのいずれかを使用する必要がある場合があります。
MikeW

9

別の方法は、出力をパイプ処理し、後続のコマンドで解析することです。これを行う唯一の安全な方法は、結果区切り文字としてヌル文字を使用する-print0ように指示findするオプションを使用することです。受信コマンドには、ヌルで区切られた入力を認識する機能が必要です。例:

find /home/phunehehe -iregex '.*\.png$' -print0 | xargs -0 file

この-0オプションはxargs、入力をヌル区切りとして扱うように指示していることに注意してください。


の代わりにを-exec付けると、さらにファイルを追加できます。カレブの答えをご覧ください。+;
ケビン

@Kevinあなたは正しいです、私は答えを更新しました。
プネヘヘ

3

Findに必要なのは、deleteコマンドが組み込まれている場合だけです。

find . -name "*.txt" -delete

見つかったすべての.txtファイルは、上記のコマンドを使用して削除されます。


2

私はこれに対する答えを探していましたが、このスレッドを見つけました。答えは私にそれを達成する方法についてのアイデアとアイディアを与えました。mediainfoすべてのJPEGファイルを見つけたいとします

これは、一致するすべてのファイルmediainfo "の先頭と"末尾に追加し(特殊文字を可能な限りエスケープするため)、スクリプトに追加してスクリプトを実行します。

find . -name *.jpg | sed -e 's/^/mediainfo "/g;' | sed -e 's/$/"/g;' > foo.sh && sh foo.sh

何かがうまくいかないことが心配な場合は、出力をファイルにリダイレクトすることをスキップして、スクリプトを実行する前にターミナルで結果を確認するだけです。


1

これを行うには、xargsコマンドを使用します。xargs基本的に、標準入力の各命令に対して1回コマンドを実行します。したがって、.jpgたとえばディレクトリ内のすべてのファイルを削除する必要がある場合、コマンドラインでの簡単な方法は次のとおりです。

$ find ./ -name "*.jpg" | xargs rm 

また、バックティック([Tab]ボタンの上)を使用してこれを行うこともできます(これは一重引用符ではなく逆引用符であることに注意してください)。

$ rm `find ./ -name "*.jpg"`

方法xargsとシェルが入力を処理するため、xargsメソッドは、関連するファイル名とディレクトリ名のいずれにも空白またはいずれかの文字が含まれていない場合にのみ機能することに注意してください\"'。バッククォート方式は、関連するファイル名とディレクトリ名のいずれにも空白またはが含まれていない場合にのみ機能します\[?*


3
これらの方法はどちらも潜在的に非常に危険であり、特にバックティックは危険です。ファイル名にエスケープされていない文字には、これらのメソッドが壊れる可能性のある多くの潜在的な問題があります。
カレブ

1
あなたの意見はわかりますが、これらのコマンドはfind以外のツールと一緒に使用することもできるので、ここで言及する価値があると思います。
IG83

言及する価値はありますが、使用しない場合指定することが重要です。ここでのOPの質問は、の出力を処理することを特に求めfind-execおり、一般的にはこれがより良い解決策です。これらを代替として指定する場合は、少なくともfind -print0 | xargs -0安全なファイル名の区切り処理に使用する方法を説明し、バッククティックに注意するタイミングを詳しく説明します。
カレブ

1
ちなみにサイトへようこそ、これが最初の答えだと思います。それを飛び越えてすみません。問題を前もって人々に教えることは重要です。そうすることで、後から見づらい間違いをしないようになりますが、なぜこれがそれほど大きな問題であるのか理解できなかった日々を覚えています。修正を個人的なものとしてはいけません。
カレブ

3
歓迎していただきありがとうございます!もちろん、難しい気持ちはありません。-execがこれを処理する適切な方法であるという点で、あなたは確かに正しいです。このプラットフォームの
素晴らしさを実感し始めまし
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.