bash find: получить каталог найденного файла

12

У меня есть родительская папка с именем «parent_folder» с множеством подпапок, в этих подпапках находится файл с именем «foo.mp4».

Я могу легко найти эти файлы, выполнив это:

mymacbook:parent_folder username$ find ./ -name "foo.mp4" -exec echo {} \;

Теперь это возвращает путь каждого файла, относительно parent_folder /

./path/to/foo.mp4

Как я могу вернуть только путь, без имени файла?

dubbelj
источник
1
man find ( ACTIONS ): -printf %h ведущие каталоги имени файла (все, кроме последнего элемента). Если имя файла не содержит косых черт (поскольку оно находится в текущем каталоге), спецификатор% h расширяется до «.» ,
Костас
Не могли бы вы показать пример этого? Должен ли я поставить это после '-exec' или до?
Дуббель
find ./ -name "foo.mp4" -printf "%h\n"напечатает путь к каждому найденному файлу (один за другим). Более того, как обычно, никто не использует, -exec echo {}поэтому есть -print(по умолчанию даже опущено) или printfдействие.
Костас
2
@Costas, -printfтолько для GNU. ОП упоминает OS / X (система BSD).
Стефан Шазелас
@ StéphaneChazelas Спасибо. Я не знал такого ограничения для OS / X (BSD). Бедные бедные пользователи Mac!
Костас

Ответы:

20

С GNUнаходкой:

 find . -name foo.mp4 -printf '%h\n'

С другими finds предоставленные имена каталогов не содержат символов новой строки:

 find . -name foo.mp4 | sed 's|/[^/]*$||'

Или:

 find . -name foo.mp4 -exec dirname {} \;

хотя это означает запуск одной dirnameкоманды на файл.

Если вам нужно выполнить команду для этого path, вы можете сделать (стандартный синтаксис):

 find . -name "featured.mp4" -exec sh -c '
   for file do
     dir=${file%/*}
     ffmpeg -i "$file" -c:v libvpx -b:v 1M -c:a libvorbis "$dir" featured.webm
   done' sh {} +

Хотя в этом случае вы можете использовать -execdir(расширение BSD также доступно в GNU find), которое chdir()находится в каталоге файла:

 find . -name "featured.mp4" -execdir \
   ffmpeg -i {} -c:v libvpx -b:v 1M -c:a libvorbis . featured.webm \;

Остерегайтесь, хотя, в то время как реализация GNU findрасширится {}до ./filenameздесь, BSD расширится до filename. Здесь все в порядке, поскольку имя файла передается в качестве аргумента опции и всегда в featured.mp4любом случае, но для других случаев вам может потребоваться принять во внимание, что имя файла может начинаться с -или +(и восприниматься командой как опция) или содержать =(и быть понятым как присвоение переменной, например, awk) или другими символами, вызывающими проблемы такого родаperl -p/n (не все из них исправлены префиксом GNU find, ./хотя в этом случае) и т. д., которые вы, возможно, должны принять во внимание ,

Стефан Шазелас
источник
Когда вы find .подаете заявление , в качестве dirname вы будете иметь. вместо всего пути.
Персидский залив
Теперь, как бы я перевести это на это? find ./ -name "featured.mp4" -exec ffmpeg -i "{}" -c:v libvpx -b:v 1M -c:a libvorbis [NEED DIRECTORY HERE] featured.webm \; Я использую второе предложение, которое вы упомянули.
Дуббель
@MohsenPahlevanzadeh, ОП не спрашивал об абсолютном пути, а о его имени.
Стефан Шазелас
@ StéphaneChazelas Извините за отклонение.
Персидский залив
Спасибо @ StéphaneChazelas. Вы помогли мне сделать очередь / пакет ffmpeg
dubbelj
-1

Команда ниже также может быть использована для получения только сведений о каталоге.

find ./ -name "foo.mp4" | rev | cut -d"/" -f2- | rev
Секар Раму
источник
Кажется немного чрезмерным вызывать три внешних утилиты только для обрезки строки.
Кусалананда