web-dev-qa-db-ja.com

「find」の「-exec」属性内で「if」を使用する方法は?

多くのファイルのペアがあるディレクトリがあります。各非テキストファイルには、テキスト記述パートナーがあります。たとえば、ディレクトリは次のようになります。

a.jpg
a.jpg.text
b.ogv
b.ogv.text
cd ef.JpG
cd ef.JpG.text

緩いテキストファイル(既に削除されたものの説明ファイル)がないことを確認したい。だから私は次を実行しようとしました:

find . -name '*.text' -exec if [ ! -f `basename -s .text {}` ]; then echo {}; fi \;

しかし、今ではエラーが発生します:

bash: syntax error near unexpected token `then'
3
v010dya

ifコマンドの-execアクションの中でfindコマンドを使用することはできません。これは、次の理由によるものです。

  • -execアクションには、commandが必要です。これはman findからのものです(私の端末の697行目):
    -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.
  • ifは、not考えられるコマンドではなく、 シェルキーワード です。 type ifコマンドの出力を参照してください。

これで、希望することを達成するために、-exec内でifを実際に使用する必要がなくなりました。 -exec内でテストを行い、-printを使用します(詳細についてはman findを参照してください)。

find . -name '*.text' -exec $Shell -c '[ ! -f ${1%.*} ]' $Shell '{}' ';' -print

別の方法は、次のようにbashスクリプトを使用することです。

find . -name '*.text' -exec my_if {} \;

ここで、cat ~/bin/my_ifは、私の場合、次の出力を提供します。

#!/bin/bash
if [ ! -f $(basename -s .text "$1") ]; then echo "$1"; fi

最後に、bashを使用するすべての普通の人は以下を使用すると思います。

for f in *.text; do if [ ! -f $(basename -s .text "$f") ]; then echo "$f"; fi; done
4
Radu Rădeanu

if句でexecを使用する最適化されていない方法を次に示します。

find . -name '*.text' -exec sh -c \
    'if [ ! -f "$(dirname "$1")/$(basename "$1" .text)" ]; then echo == $1; fi' sh {} \;

また、ファイルごとに1つのシェルを起動しない、はるかに優れたものがあります。

find . -name '*.text' -exec sh -c \
    'for i do if [ ! -f "${i%.text}" ]; then echo == $i; fi;done' sh {} +
3
jlliagre