bash find: obtiene el directorio del archivo encontrado

12

Tengo una carpeta principal llamada "parent_folder" con muchas subcarpetas, en estas subcarpetas hay un archivo llamado "foo.mp4".

Puedo encontrar estos archivos fácilmente haciendo esto:

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

Ahora que devuelve la ruta de cada archivo, en relación con parent_folder /

./path/to/foo.mp4

¿Cómo puedo devolver solo la ruta, sin el nombre del archivo?

dubbelj
fuente
1
man find ( ACTIONS ): -printf %h directorios principales del nombre del archivo (todos menos el último elemento). Si el nombre del archivo no contiene barras (ya que está en el directorio actual), el especificador% h se expande a "." .
Costas
¿Podría mostrar un ejemplo de eso? ¿Debo poner eso detrás de '-exec' o antes?
dubbelj
find ./ -name "foo.mp4" -printf "%h\n"imprimirá la ruta para cada archivo encontrado (uno por línea). Más de lo habitual, nadie lo usa, -exec echo {}por lo tanto, hay -print(omisión incluso omitida) o printfacción.
Costas
2
@ Costas, -printfes solo GNU. El OP menciona OS / X (un sistema BSD).
Stéphane Chazelas
@ StéphaneChazelas Gracias. No conocía esa limitación para OS / X (BSD). ¡Pobres usuarios pobres de mac!
Costas

Respuestas:

20

Con GNUencontrar:

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

Con otros finds, los nombres de directorio proporcionados no contienen caracteres de nueva línea:

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

O:

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

aunque eso significa ejecutar un dirnamecomando por archivo.

Si necesita ejecutar un comando sobre eso path, puede hacer (sintaxis estándar):

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

Aunque en este caso, puede usar -execdir(una extensión BSD también disponible en GNU find), que chdir()está en el directorio del archivo:

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

Sin embargo, findtenga en cuenta que si bien la implementación de GNU se expandirá {}hasta ./filenameaquí, las de BSD también filename. Está bien aquí, ya que el nombre de archivo se pasa como argumento a una opción y siempre es de todos featured.mp4modos, pero para otros usos, es posible que tenga que tener en cuenta que el nombre del archivo puede comenzar con -o +(y el comando lo puede entender como una opción) o contener =(y debe entenderse como una asignación variable por awk por ejemplo), u otros caracteres que causan este tipo de problema conperl -p/n (no todos ellos arreglados por findel ./prefijo de GNU en ese caso), etc., que puede tener que tener en cuenta .

Stéphane Chazelas
fuente
Cuando lo solicites find ., como dirname tendrás. en lugar de todo el camino.
PersianGulf
Ahora, ¿cómo traduciría eso a esto? find ./ -name "featured.mp4" -exec ffmpeg -i "{}" -c:v libvpx -b:v 1M -c:a libvorbis [NEED DIRECTORY HERE] featured.webm \; Estoy usando la segunda sugerencia que mencionaste.
dubbelj
@MohsenPahlevanzadeh, el OP no solicitó una ruta absoluta, sino el nombre del directorio de la ruta.
Stéphane Chazelas
@ StéphaneChazelas Perdón por votar.
PersianGulf
Gracias @ StéphaneChazelas. Me ayudaste a hacer una cola / lote ffmpeg
dubbelj
-1

El siguiente comando también se puede utilizar para obtener solo los detalles del directorio.

find ./ -name "foo.mp4" | rev | cut -d"/" -f2- | rev
Sekar Ramu
fuente
Parece un poco excesivo llamar a tres utilidades externas solo para recortar una cadena.
Kusalananda