¿Cómo uso `find` para ir al directorio de ese archivo

11

Quiero encontrar un archivo y luego ingresar al directorio que lo contiene. Lo intenté find /media/storage -name "Fedora" | xargs cdpero, por supuesto, el is not a directoryerror.

¿Cómo ingreso su directorio padre con un comando de una línea?

Hrvoje T
fuente
1
¿Y qué pasa si hay varios archivos de varias ubicaciones?
Sergiy Kolodyazhnyy
@Serg Estoy buscando el archivo Fedora * .iso y sé que solo hay uno. Si hubiera más de uno, entraría en la primera dirección, supongo
Hrvoje T
En contra shopt -s globstar, podría cd /media/storage/**/Fedora, pero eso no deja de evaluar el glob en la primera coincidencia (por lo que es más lento que la solución de Steeldriver. Para uso interactivo, lo que normalmente haría es alcanzar el mouse y copiar / pegar el nombre del directorio, (y alt + retroceso según sea necesario para quitar los componentes de ruta de acceso que no quería), pero si haces esto mucho, supongo que valdría la pena hacer una función de shell.
Peter Cordes
1
Por cierto, xargs cdno puede funcionar. cdsolo puede funcionar como un shell incorporado, ya que tiene que modificar el contexto del shell en sí. No hay forma de que un xargsproceso secundario pueda hacer eso. IDK si eso es lo que quiso decir con "por supuesto", o si la ruta que se findimprime contiene espacios, que se dividen en xargs ya que no los usó -d \nni nada. O find -exec {} \;.
Peter Cordes
nota: no puedes correr cdasí. cdes un bash incorporado, si cdfuera un comando separado, entonces cambiaría (su propio) directorio, y luego se cerraría (regresando al shell, que está en el mismo estado que antes, sin cambio de directorio).
ctrl-alt-delor

Respuestas:

14

Al menos si tiene GNU find, puede usar -printf '%h'para obtener el directorio

       %h     Leading directories of file's name (all but the last ele‐
              ment).  If the file name contains no slashes (since it is
              in  the  current  directory)  the %h specifier expands to
              ".".

Entonces probablemente podrías hacer

cd "$(find /media/storage -name "Fedora" -printf '%h' -quit)"

El -quitdebe evitar que varios argumentos que cden el caso de más de un archivo coincide.

conductor de acero
fuente
1
-quittampoco es necesariamente compatible. En NetBSD se llama -exit, consulte unix.stackexchange.com/a/62883/117599
phk
2
Si no hay printf, ¿podría hacer -exec dirname en su lugar?
Chico
@ Buena idea, sí, eso parece que también debería funcionar
steeldriver
6

Similar a la solución de steeldriver pero usando -execdir(si lo findadmite, como GNU o FreeBSD find) en combinación con pwd:

cd "$(find /media/storage -name "Fedora" -execdir pwd \; -quit)"

-quites opcional en caso de que solo haya un único resultado y rastrear todo el directorio no sea un problema. En NetBSD es -exity en OpenBSD no existe.

phk
fuente
¿Y para qué sirve \;?
Hrvoje T
1
@HrvojeT Al igual -execque dice findsobre el final de los parámetros para que se ejecute el comando. Pero dado que queremos llamar pwdsin parámetros aquí, ponemos el \;derecho después.
phk
¿Hay findimplementaciones que admitan execdir pero no -printf %h? Me parece poco probable. Lamentablemente, POSIX no requiere ninguno: /
Peter Cordes
1
@PeterCordes FreeBSD's find: freebsd.org/cgi/man.cgi?find%281%29 (Acabo de confirmarlo en una instalación de FreeBSD 11.)
phk
@PeterCordes Lo mismo para NetBSD ( netbsd.gw.com/cgi-bin/man-cgi?find++NetBSD-current ) y OpenBSD ( man.openbsd.org/OpenBSD-current/man1/find.1 ). Últimamente no es compatible -quit/ -exiten absoluto.
phk
5

Puede hacer que find ejecute un nuevo shell en el directorio que encuentre.

exec find /media/storage -name "Fedora" -execdir "$SHELL" \;

, después de lo cual el directorio actual será el que tenga un archivo llamado Fedora. ;)

Obviamente, esto solo hace algo parecido a lo que desea si está escribiendo comandos de forma interactiva.

BenGoldberg
fuente
4

Con zsh:

cd /media/storage/**/Fedora([1]:h)

que cden el primer directorio (en orden alfabético) que contiene un archivo llamado Fedora.

  • **: cualquier nivel de directorios (los directorios ocultos se omiten de forma predeterminada, use el Dcalificador global para incluirlos)
  • [1]: solo el primero
  • :h: modificador de cabeza : toma el nombre del directorio.

Al contrario cd "$(find ...)", también funciona si el nombre del directorio termina en un carácter de nueva línea. Otra ventaja es que se obtendría un partido sin mensaje de error cuando no hay coincidencia de directorio (mientras que en la mayoría de los proyectiles cd ""no haría nada en silencio).

Un inconveniente es que se arrastraría todo /media/storageantes de regresar.

Stéphane Chazelas
fuente
En bash, cdcon múltiples argumentos solo mira el primer argumento de todos modos, por cd $(dirname /media/storage/**/Fedora)lo que funcionaría (con shopt -s globstar) si no hay espacios en la ruta. Para conseguirlo citado correctamente, creo que una matriz bash es más fácil: target=(/media/storage/**/Fedora); cd "${target%/*}". Pero en ese punto habría sido más rápido usar el mouse para copiar / pegar resultados de búsqueda en lugar de crearlos de forma interactiva.
Peter Cordes
2
@PeterCordes, muchas dirnameimplementaciones no aceptarán más de un argumento. Tenga en cuenta que no son espacios , es cualquier carácter actualmente en $IFS(espacio, tabulación y nueva línea por defecto) y caracteres comodín. Tenga en cuenta que si bash's cdaceptarán más de un argumento depende de la forma en que fue compilado ( CD_COMPLAINSen config-top.h). Uno puede imaginar que las versiones futuras de basheventualmente también implementarán las dos características arg como en zsh.
Stéphane Chazelas
Gracias. Acabo de mirar la página de manual de GNU coreutils dirname. La versión dirname es terrible de todos modos; Solo lo mencioné como algo que podrías probar de forma interactiva en caso de que funcione. Mi versión basada en matriz no sufre ninguno de esos problemas, ya que se "${target%*/}"expande solo al primer elemento de matriz (con el /Fedoradespojado). Creo que esa versión es completamente robusta contra cualquier posible personaje en la ruta.
Peter Cordes