bash find: récupère le répertoire du fichier trouvé

12

J'ai un dossier parent nommé "parent_folder" avec beaucoup de sous-dossiers, dans ces sous-dossiers se trouve un fichier nommé "foo.mp4".

Je peux trouver ces fichiers facilement en faisant ceci:

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

Maintenant, cela renvoie le chemin de chaque fichier, par rapport à parent_folder /

./path/to/foo.mp4

Comment puis-je retourner uniquement le chemin, sans le nom de fichier?

dubbelj
la source
1
man find ( ACTIONS ): -printf %h principaux répertoires du nom du fichier (tous sauf le dernier élément). Si le nom de fichier ne contient aucune barre oblique (car il se trouve dans le répertoire en cours), le spécificateur% h se développe en "." .
Costas
Pourriez-vous en montrer un exemple? Dois-je mettre cela derrière «-exec» ou avant?
dubbelj
find ./ -name "foo.mp4" -printf "%h\n"affichera le chemin d'accès à chaque fichier trouvé (un par ligne). De plus, comme d'habitude, personne n'utilise -exec echo {}donc il y a -print(défaut même omis) ou printfaction.
Costas
2
@Costas, -printfest uniquement GNU. L'OP mentionne OS / X (un système BSD).
Stéphane Chazelas
@ StéphaneChazelas Merci. Je ne connaissais pas une telle limitation pour OS / X (BSD). Pauvres pauvres utilisateurs de mac!
Costas

Réponses:

20

Avec GNUfind:

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

Avec les autres finds, les noms de répertoire fournis ne contiennent pas de caractères de nouvelle ligne:

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

Ou:

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

bien que cela signifie exécuter une dirnamecommande par fichier.

Si vous devez exécuter une commande à ce sujet path, vous pouvez le faire (syntaxe standard):

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

Bien que dans ce cas, vous puissiez utiliser -execdir(une extension BSD également disponible dans GNU find), qui se trouve chdir()dans le répertoire du fichier:

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

Attention cependant, bien que l'implémentation GNU de finds'étende {}jusqu'à ./filenameici, celles de BSD s'étendent jusqu'à filename. C'est OK ici car le nom de fichier est passé comme argument à une option et est toujours de featured.mp4toute façon, mais pour d'autres utilisations, vous devrez peut-être tenir compte du fait que le nom de fichier peut commencer par -ou +(et être compris comme une option par la commande) ou contenir =(et être compris comme une affectation de variable par awk par exemple), ou d'autres caractères causant ce genre de problèmeperl -p/n (mais pas tous corrigés par findle ./préfixe de GNU dans ce cas), etc., dont vous devrez peut-être tenir compte .

Stéphane Chazelas
la source
Lorsque vous postulez find ., vous aurez comme dirname. au lieu du chemin entier.
PersianGulf
Maintenant, comment pourrais-je traduire cela en ceci? find ./ -name "featured.mp4" -exec ffmpeg -i "{}" -c:v libvpx -b:v 1M -c:a libvorbis [NEED DIRECTORY HERE] featured.webm \; J'utilise la deuxième suggestion que vous avez mentionnée.
dubbelj
@MohsenPahlevanzadeh, l'OP n'a pas demandé de chemin absolu, mais le nom de dir du chemin.
Stéphane Chazelas
@ StéphaneChazelas Désolé pour voter contre.
PersianGulf
Merci @ StéphaneChazelas. Vous m'avez aidé à faire une file d'attente / batch ffmpeg
dubbelj
-1

La commande ci-dessous peut également être utilisée pour récupérer uniquement les détails du répertoire.

find ./ -name "foo.mp4" | rev | cut -d"/" -f2- | rev
Sekar Ramu
la source
Il semble un peu excessif d'appeler trois utilitaires externes juste pour couper une chaîne.
Kusalananda