webdevqa.jp.net

findコマンドでdirnameを使用すると、一致ごとにドットが表示されるのはなぜですか?

タスクにfindを使用していますが、次のようなことをすると気付きました。

find `pwd` -name "file.ext" -exec echo $(dirname {}) \;

試合ごとにのみドットが表示されます。そのコマンドでdirnamebasenameに置き換えると、完全なパス名が得られます。私はここで何かを台無しにしていますか、これは予想される動作ですか?私はbasenameにファイルの名前を与えるのに慣れています(この場合はfile.ext)とdirnameは、パスの残りの部分を示します。

33
temp2290

次のスクリプトについて考えてみます。

_#!/bin/sh
set -x
find `pwd` -name "file.ext" -exec echo $(dirname {}) \;
_

_set -x_は、展開の仕組みと最終的なコマンドを示しています。実行すると、次の出力が表示されます。

_++ pwd
++ dirname '{}'
+ find /home/kibab -name file.ext -exec echo . ';'
_

したがって、最初に展開されるのはpwdです。 2番目は$(dirname {})です。これら2つのコマンドの結果は、findコマンドにドロップされます。したがって、findに_-exec echo ._を指示しているので、期待される出力が表示されます。

basenamedirnameに置き換えても、展開は行われますが、展開の結果は異なります。

  1. pwdは現在のパスに展開されます。上記の例では、結果は_/home/kibab_です。
  2. _basename {}_が実行されます。このコマンドの結果は_{}_です。
  3. 上記の置換を行った状態でfindコマンドが実行されます。実行される最後のコマンドは次のようになります。

    _find /home/kibab -name '*.png' -exec echo '{}' ';'_

上記のコマンドを調べると、コマンドが見つかったファイルをエコーするだけであることがわかります。

おそらくあなたはこのようなものを望んでいますか?

_find `pwd` -name "file.ext" -printf "%f\n"
_
28
Kaleb Pederson

つまり問題は、$(...)または `...`が新しいシェルを開始してから置換を行うことです。

Bash -cの使用を検討してください:

$ find . -name '*.PNG' -exec bash -c 'git mv {} $(dirname {})/$(basename {} .PNG)48.png' \;

これにより、gitリポジトリのアイコンの名前がより標準的な形式に変更されます。

ここで{}は何かを実行する前に置き換えられるため、問題はなくなりました。

その例では、TMTOWTDIですが、本当に必要なことは何でも開始できるように、シンプルに保つようにしています。

25
albfan

見つかったファイルごとにdirname()を呼び出す必要はありません。 GNU findを使用すると、-printfそしてそのより速いこの方法

find /path -type f -iname "*.ext" -printf "%h\n"
8
ghostdog74

$(dirname {})は、findに渡される前にシェルによって評価されます。この評価の結果は_._なので、検出した各ファイルに対して_echo ._を実行するようにfindに指示するだけです。

_basename {}_は_{}_に評価されるため、$(basename {})$(dirname {})に置き換えると、findは各ファイルに対して_echo {}_を実行します。これにより、各ファイルの完全な名前がエコーされます。

見つかったファイルごとにdirnameの結果を出力する場合は、echoを省略できます。

_find `pwd` -name "file.ext" -exec dirname {} \;
_
6
Phil Ross

コマンドが実際に実行される前にプロセス置換が評価されるので、ドットが表示されます。したがって、コマンドを別のシェルインスタンスに渡す必要があります。

回避策として、次の構文を使用します。

find $PWD -name "file.ext" -exec sh -c 'echo $(dirname {})' ';'

ただし、各ディレクトリで何かを印刷または実行する最も簡単な方法は、-execdirによるものです。例:

find . -name "file.ext" -execdir pwd ';'
5
kenorb

なぜそれが得られるのかわかりませんが、これを試してください:

find `pwd` -name file.ext |xargs -l1 dirname
4
Paul Tomblin

これは、findが検索するパスからの相対パスを出力するためです。 /からこの検索を試みた場合、各パスに対して `` pwd\を取得します。

0
pajton