bash find: obtém o diretório do arquivo encontrado

12

Eu tenho uma pasta pai chamada "parent_folder" com muitas subpastas, nessas subpastas existe um arquivo chamado "foo.mp4".

Eu posso encontrar esses arquivos facilmente fazendo o seguinte:

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

Agora que retorna o caminho de cada arquivo, relativo a parent_folder /

./path/to/foo.mp4

Como posso retornar apenas o caminho, sem o nome do arquivo?

dubbelj
fonte
1
man find ( ACTIONS ): -printf %h Diretórios principais do nome do arquivo (todos, exceto o último elemento). Se o nome do arquivo não contiver barras (já que está no diretório atual), o especificador% h será expandido para "." .
Costas
Você poderia mostrar um exemplo disso? Devo colocar isso atrás de '-exec' ou antes?
dubbelj
find ./ -name "foo.mp4" -printf "%h\n"imprimirá o caminho para cada arquivo encontrado (um por linha). Mais do que o habitual, ninguém usa, -exec echo {}portanto, existe -print(padrão omitido) ou printfação.
Costas
2
@Costas, -printfé apenas GNU. Os OPs mencionam o OS / X (um sistema BSD).
Stéphane Chazelas
@ StéphaneChazelas Obrigado. Eu não conhecia essa limitação para o OS / X (BSD). Pobres usuários pobres de mac!
Costas

Respostas:

20

Com GNUencontrar:

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

Com outros finds, os nomes de diretório fornecidos não contêm caracteres de nova linha:

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

Ou:

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

embora isso signifique executar um dirnamecomando por arquivo.

Se você precisar executar um comando path, poderá fazer (sintaxe padrão):

 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 {} +

Embora neste caso, você possa usar -execdir(uma extensão BSD também disponível no GNU find), que chdir()é o diretório do arquivo:

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

Cuidado, porém, embora a implementação do GNU findse expanda {}para ./filenameaqui, os do BSD se expandam para filename. Tudo bem aqui, já que o nome do arquivo é passado como argumento para uma opção e sempre é featured.mp4assim mesmo, mas para outros usos, talvez seja necessário levar em consideração que o nome do arquivo pode começar com -ou +(e ser entendido como uma opção pelo comando) ou conter =(e ser entendido como uma atribuição de variável pelo awk, por exemplo), ou outros caracteres que causam esse tipo de problemaperl -p/n (nem todos eles foram corrigidos pelo prefixo do GNU find, ./nesse caso), etc, que talvez você precise levar em consideração .

Stéphane Chazelas
fonte
Quando você se inscrever find ., como dirname você terá. em vez de todo o caminho.
precisa saber é o seguinte
Agora, como eu traduziria isso para isso? find ./ -name "featured.mp4" -exec ffmpeg -i "{}" -c:v libvpx -b:v 1M -c:a libvorbis [NEED DIRECTORY HERE] featured.webm \; Estou usando a segunda sugestão que você mencionou.
dubbelj
@MohsenPahlevanzadeh, o OP não pediu um caminho absoluto, mas o nome do diretório.
Stéphane Chazelas
@ StéphaneChazelas Desculpe pela votação.
precisa saber é o seguinte
Obrigado @ StéphaneChazelas. Você me ajudou a fazer uma ffmpeg fila / batch
dubbelj
-1

O comando abaixo também pode ser usado para buscar apenas os detalhes do diretório.

find ./ -name "foo.mp4" | rev | cut -d"/" -f2- | rev
Sekar Ramu
fonte
Parece um pouco excessivo chamar três utilitários externos apenas para aparar uma string.
Kusalananda