Почему использование dirname в команде find дает точки для каждого совпадения?
Я использую find для задачи, и я заметил, что когда я делаю что-то вроде этого:
find `pwd` -name "file.ext" -exec echo $(dirname {}) \;
он даст вам точки только для каждого матча. Когда вы заменяете dirname
на basename
в этой команде, вы получаете полные пути. Я что-то прикручиваю здесь или это ожидаемое поведение? Я привык к basename
, давая вам имя файла (в данном случае file.ext
) и dirname
, давая вам остальную часть пути.
Ответы
Ответ 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
, расширение все еще занимает место, но результаты разложения разные:
При проверке приведенной выше команды вы заметите, что команда теперь просто эхо файл, который был найден.
Возможно, вам нужно что-то вроде этого?
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 \
для каждого пути.