Подтвердить что ты не робот

Почему использование dirname в команде find дает точки для каждого совпадения?

Я использую find для задачи, и я заметил, что когда я делаю что-то вроде этого:

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

он даст вам точки только для каждого матча. Когда вы заменяете dirname на basename в этой команде, вы получаете полные пути. Я что-то прикручиваю здесь или это ожидаемое поведение? Я привык к basename, давая вам имя файла (в данном случае file.ext) и dirname, давая вам остальную часть пути.

4b9b3361

Ответ 1

Рассмотрим следующий script:

#!/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. Второй - $(dirname {}). Результат этих двух команд затем отбрасывается в команду find. Таким образом, вы указываете find на -exec echo ., поэтому вы видите ожидаемый результат.

Когда вы заменяете basename на dirname, расширение все еще занимает место, но результаты разложения разные:

  • pwd расширяется до текущего пути. В моем примере выше результат /home/kibab Выполняется
  • basename {}. Результатом этой команды является {}.
  • Команда find выполняется с указанными выше заменами. Завершенная команда выглядит следующим образом:

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

При проверке приведенной выше команды вы заметите, что команда теперь просто эхо файл, который был найден.

Возможно, вам нужно что-то вроде этого?

find `pwd` -name "file.ext" -printf "%f\n"

Ответ 2

Таким образом, проблема заключается в том, что $(...) или `...` запускает новую оболочку перед заменой.

Рассмотрим использование bash -c:

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

Это переименовывает любой значок в репозитории git в более стандартную форму.

Здесь {} заменяется перед выполнением чего-либо, поэтому проблема исчезла.

В этом примере TMTOWTDI, но я стараюсь держать его простым, чтобы вы могли начать все, что вам действительно нужно делать.

Ответ 3

вам не нужно вызывать dirname() для каждого найденного файла. с GNU find, вы можете использовать -printf и быстрее его

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

Ответ 4

Я не знаю, почему вы это поняли, но попробуйте следующее:

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

Ответ 5

$(dirname {}) оценивается оболочкой перед передачей в find. Результатом этой оценки является ., поэтому вы просто сообщаете find выполнить echo . для каждого найденного файла.

basename {} оценивается как {}, поэтому при $(basename {}), замененном на $(dirname {}), find выполнит echo {} для каждого файла. Это приводит к полному имени каждого файла, который будет эхом.

Если вы хотите вывести результат dirname для каждого найденного файла, вы можете опустить echo:

find `pwd` -name "file.ext" -exec dirname {} \;

Ответ 6

Он показывает вам точки, потому что подстановка процесса оценивается до того, как команда фактически выполняется. Поэтому вам нужно передать команду в отдельный экземпляр оболочки.

Что касается обходного пути, используйте следующий синтаксис:

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

Однако самый простой способ распечатать или выполнить что-либо в каждом каталоге - -execdir, например:

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

Ответ 7

Это связано с тем, что find печатает пути относительно пути, из которого выполняется поиск. Если вы попытались выполнить поиск из /, вы получите `` pwd \ для каждого пути.