encontrar seches dentro del camino dado incluido como se indica. Entonces, si ingresó ./, no coincidiófoo
Costas
@ Costas: Entiendo eso. Lo que no entiendo es por qué ha marcado la diferencia si le doy el camino absoluto find.
York
@York En ciertas situaciones no existe un comportamiento que siempre sea correcto. Imagine un enlace simbólico con el nombre barque apunta a un archivo fooque está fuera de la ruta de búsqueda. ¿Esa coincidencia o no?
Hauke Laging
1
Los .y /tmp/foono son lo mismo: son dos enlaces duros diferentes al mismo directorio; find /tmp/foo/. -name 'foo'tampoco encuentra nada.
jimmij
@jimmij: cuando ejecuto find /tmp/foo -name 'foo', le pedía a bash que buscara en el directorio /tmp/fooun archivo cuyo nombre es "foo". Como el directorio /tmp/fooestá vacío, no debería haber devuelto nada. No entiendo por qué vuelve /tmp/foo. Por otro lado, cuando corro find . -name 'foo', le estaba preguntando a bash lo mismo, es decir, encontrar un archivo en el directorio actual (que resultó ser /tmp/foo), cuyo nombre es 'foo', y no devuelve nada que tenga sentido.
York
Respuestas:
15
findatraviesa los árboles de directorios especificados y evalúa la expresión dada para cada archivo que encuentra. El recorrido comienza en el camino dado. Aquí hay un resumen de cómo find . -name foofunciona:
Primera ruta en la línea de comando: .
¿El nombre base ( .) coincide con el patrón foo? No, entonces no hagas nada.
Sucede que /tmp/fooes otro nombre para el mismo directorio. Pero findno lo sabe (y se supone que no debe intentar averiguarlo).
¿Es la ruta un directorio? Sí, entonces atravesarlo. Enumere las entradas .y, para cada entrada, realice el proceso transversal.
El directorio está vacío: no contiene ninguna entrada que no sea .y .., que findno recorre recursivamente. Entonces el trabajo está terminado.
Y find /tmp/foo:
Primera ruta en la línea de comando: /tmp/foo
¿El nombre base ( foo) coincide con el patrón foo? Sí, entonces la condición coincide.
No hay ninguna acción asociada con esta condición, por lo tanto, realice la acción predeterminada, que es imprimir la ruta.
¿Es la ruta un directorio? Sí, entonces atravesarlo. Enumere las entradas /tmp/fooy, para cada entrada, realice el proceso transversal.
El directorio está vacío: no contiene ninguna entrada que no sea .y .., que findno recorre recursivamente. Entonces el trabajo está terminado.
Se da la circunstancia de que .y /tmp/fooson el mismo directorio, pero eso no es suficiente para garantizar que findtiene el mismo comportamiento en ambos. El findcomando tiene formas de distinguir entre rutas al mismo archivo; El -namepredicado es uno de ellos. find /tmp/foo -name foocoincide con el directorio de inicio, así como con cualquier archivo debajo que se llame foo. find . -name .solo coincide con el directorio inicial ( .nunca se puede encontrar durante un recorrido recursivo).
"no contiene ninguna entrada que no sea. y ..., que find no atraviesa recursivamente". Supongo que "no atraviesa recursivamente" se refieren a "..". Si eso es correcto, ¿qué significaría "transversal recursivamente" en el contexto de ".."?
Faheem Mitha
@FaheemMitha "no atraviesa recursivamente" se aplica a ambos .y ... (Si se findatraviesa .recursivamente, terminaría yendo a través del directorio una y otra y otra vez y ...) .y ..no son solo anotaciones especiales, aparecen como entradas de directorio.
Gilles 'SO- deja de ser malvado'
5
No hay normalización de los argumentos de la línea de comando antes de que se apliquen las pruebas. Por lo tanto, los resultados difieren dependiendo de la ruta utilizada (si están involucrados enlaces simbólicos):
cd /tmp
mkdir foo
ln -s foo bar
find /tmp/foo -name foo
find /tmp/bar -name foo
En "su caso" ambas llamadas darían el mismo resultado que podría ser (más) confuso. Puede usarlo -mindepth 1si desea que se ignoren los puntos de partida (puede que no sean POSIX).
-mindepth 1trabajos. Sin embargo, todavía no entiendo por qué find . -name 'foo'y me find /tmp/foo -name 'foo'comporto de manera diferente.
York
2
(gnu) find muestra las coincidencias encontradas dentro de la ruta proporcionada al comando porque comienza su comparación con los argumentos de la línea de comandos, descendiendo más profundamente en la estructura del directorio desde allí (por lo tanto, -maxdepth 0limita las pruebas al nivel base o solo a los argumentos de la línea de comandos, mientras que -mindepth 1omite los argumentos de la línea de comandos como se man findexplica Esta es la razón por la find /tmp/foo -name 'foo'cual producirá una coincidencia incluso si el directorio en sí está vacío.
find . -name 'foo'por otro lado, no dará ningún resultado porque .(punto) es un archivo especial que actúa como un enlace rígido al mismo inodo que /tmp/foo: es como un nombre de archivo separado (aunque especial) y no un enlace simbólico o una expresión sujeta a expansión del nombre de ruta por el shell. Por lo tanto, la primera prueba aplicada por find a los argumentos de la línea de comandos en el ejemplo dado no mostrará coincidencias, ya que de .hecho no coincide con el patrón de nombre definido en -name 'foo'. Tampoco lo hace, /tmp/foo/.ya que una prueba para un -namepatrón se realiza solo en el nombre base de la ruta (ver man find), que aquí está nuevamente ..
Si bien este comportamiento puede no esperarse o parecer intuitivo desde la perspectiva del usuario (y sí, al principio también me confundió), no constituye un error, sino que corresponde con la lógica y la funcionalidad descritas en las páginas de manual e información para ( ñu) encontrar.
Intenté comentar la respuesta de Gilles, pero fue demasiado largo para caber en un comentario. Por esta razón, lo pongo como respuesta a mi propia pregunta.
La explicación de Gilles (y la de Shevek también) es clara y tiene sentido. El punto clave aquí es que no solo findintenta hacer coincidir los nombres de archivo para los archivos dentro de las rutas dadas (recursivamente), sino que también trata de hacer coincidir el nombre base de las rutas dadas.
Por otro lado, ¿hay alguna prueba de que esta es la forma en que findse supone que funciona, en lugar de ser un error? En mi opinión, sería mejor si no hace que los resultados sean inconsistentes find .y find ABSOLUTE-PATHporque la inconsistencia siempre es confusa y podría desperdiciar mucho tiempo al desarrollador tratando de descubrir "qué estaba mal". En mi caso, estaba escribiendo un guión, y la ruta se tomó de una variable. Entonces, para que mi script funcione correctamente, lo que puedo pensar es escribir find $path/. -name 'pattern'.
Finalmente, creo que se pueden obtener resultados consistentes findal sustituir siempre .el directorio actual por el directorio actual antes de continuar.
No hay ningún objeto nombrado fooen el directorio donde inició la búsqueda relativa.
Está en lo cierto al suponer que gfindtiene errores cuando informa /tmp/foocuando se usa el nombre absoluto como directorio de inicio.
Gfindtiene varias desviaciones del estándar, parece que encontraste otra. Cuando desee una solución compatible más estándar, le recomiendo sfindque sea parte del schilytools.
-namese aplica a los resultados de búsqueda del directorio. Ninguno de los dos casos que menciona devolverá una entrada de directorio foode una readdir()operación.
Sospecho que esto también es un error. Aquí está el resultado de find --version: find (GNU findutils) 4.4.2 Copyright (C) 2007 Free Software Foundation, Inc. Licencia GPLv3 +: GNU GPL versión 3 o posterior < gnu.org/licenses/gpl.html >
York
Bueno, verifiqué sus comandos de ejemplo con find(certificado POSIX) gfindy sfind; el problema solo existe cuando lo usas gfind. En Linux, gfindno se instala con su nombre nativo sino con el nombre find.
schily
3
Es correcto para la find /tmp/foo -name foosalida /tmp/foo. (Cc @York) Este es el comportamiento de OpenBSD find, GNU find, BusyBox find, Solaris findy cualquier otro compatible con POSIX find("El primario evaluará como verdadero si el nombre base del nombre del archivo que se examina coincide con el patrón (...)" - cuando el nombre del archivo es uno que se pasa como un operando de ruta, no hay readdirllamadas involucradas).
./
, no coincidiófoo
find
.bar
que apunta a un archivofoo
que está fuera de la ruta de búsqueda. ¿Esa coincidencia o no?.
y/tmp/foo
no son lo mismo: son dos enlaces duros diferentes al mismo directorio;find /tmp/foo/. -name 'foo'
tampoco encuentra nada.find /tmp/foo -name 'foo'
, le pedía a bash que buscara en el directorio/tmp/foo
un archivo cuyo nombre es "foo". Como el directorio/tmp/foo
está vacío, no debería haber devuelto nada. No entiendo por qué vuelve/tmp/foo
. Por otro lado, cuando corrofind . -name 'foo'
, le estaba preguntando a bash lo mismo, es decir, encontrar un archivo en el directorio actual (que resultó ser/tmp/foo
), cuyo nombre es 'foo', y no devuelve nada que tenga sentido.Respuestas:
find
atraviesa los árboles de directorios especificados y evalúa la expresión dada para cada archivo que encuentra. El recorrido comienza en el camino dado. Aquí hay un resumen de cómofind . -name foo
funciona:.
.
) coincide con el patrónfoo
? No, entonces no hagas nada.Sucede que
/tmp/foo
es otro nombre para el mismo directorio. Perofind
no lo sabe (y se supone que no debe intentar averiguarlo)..
y, para cada entrada, realice el proceso transversal..
y..
, quefind
no recorre recursivamente. Entonces el trabajo está terminado.Y
find /tmp/foo
:/tmp/foo
foo
) coincide con el patrónfoo
? Sí, entonces la condición coincide./tmp/foo
y, para cada entrada, realice el proceso transversal..
y..
, quefind
no recorre recursivamente. Entonces el trabajo está terminado.Se da la circunstancia de que
.
y/tmp/foo
son el mismo directorio, pero eso no es suficiente para garantizar quefind
tiene el mismo comportamiento en ambos. Elfind
comando tiene formas de distinguir entre rutas al mismo archivo; El-name
predicado es uno de ellos.find /tmp/foo -name foo
coincide con el directorio de inicio, así como con cualquier archivo debajo que se llamefoo
.find . -name .
solo coincide con el directorio inicial (.
nunca se puede encontrar durante un recorrido recursivo).fuente
.
y..
. (Si sefind
atraviesa.
recursivamente, terminaría yendo a través del directorio una y otra y otra vez y ...).
y..
no son solo anotaciones especiales, aparecen como entradas de directorio.No hay normalización de los argumentos de la línea de comando antes de que se apliquen las pruebas. Por lo tanto, los resultados difieren dependiendo de la ruta utilizada (si están involucrados enlaces simbólicos):
En "su caso" ambas llamadas darían el mismo resultado que podría ser (más) confuso. Puede usarlo
-mindepth 1
si desea que se ignoren los puntos de partida (puede que no sean POSIX).fuente
-mindepth 1
trabajos. Sin embargo, todavía no entiendo por quéfind . -name 'foo'
y mefind /tmp/foo -name 'foo'
comporto de manera diferente.(gnu) find muestra las coincidencias encontradas dentro de la ruta proporcionada al comando porque comienza su comparación con los argumentos de la línea de comandos, descendiendo más profundamente en la estructura del directorio desde allí (por lo tanto,
-maxdepth 0
limita las pruebas al nivel base o solo a los argumentos de la línea de comandos, mientras que-mindepth 1
omite los argumentos de la línea de comandos como seman find
explica Esta es la razón por lafind /tmp/foo -name 'foo'
cual producirá una coincidencia incluso si el directorio en sí está vacío.find . -name 'foo'
por otro lado, no dará ningún resultado porque.
(punto) es un archivo especial que actúa como un enlace rígido al mismo inodo que/tmp/foo
: es como un nombre de archivo separado (aunque especial) y no un enlace simbólico o una expresión sujeta a expansión del nombre de ruta por el shell. Por lo tanto, la primera prueba aplicada por find a los argumentos de la línea de comandos en el ejemplo dado no mostrará coincidencias, ya que de.
hecho no coincide con el patrón de nombre definido en-name 'foo'
. Tampoco lo hace,/tmp/foo/.
ya que una prueba para un-name
patrón se realiza solo en el nombre base de la ruta (verman find
), que aquí está nuevamente.
.Si bien este comportamiento puede no esperarse o parecer intuitivo desde la perspectiva del usuario (y sí, al principio también me confundió), no constituye un error, sino que corresponde con la lógica y la funcionalidad descritas en las páginas de manual e información para ( ñu) encontrar.
fuente
Intenté comentar la respuesta de Gilles, pero fue demasiado largo para caber en un comentario. Por esta razón, lo pongo como respuesta a mi propia pregunta.
La explicación de Gilles (y la de Shevek también) es clara y tiene sentido. El punto clave aquí es que no solo
find
intenta hacer coincidir los nombres de archivo para los archivos dentro de las rutas dadas (recursivamente), sino que también trata de hacer coincidir el nombre base de las rutas dadas.Por otro lado, ¿hay alguna prueba de que esta es la forma en que
find
se supone que funciona, en lugar de ser un error? En mi opinión, sería mejor si no hace que los resultados sean inconsistentesfind .
yfind ABSOLUTE-PATH
porque la inconsistencia siempre es confusa y podría desperdiciar mucho tiempo al desarrollador tratando de descubrir "qué estaba mal". En mi caso, estaba escribiendo un guión, y la ruta se tomó de una variable. Entonces, para que mi script funcione correctamente, lo que puedo pensar es escribirfind $path/. -name 'pattern'
.Finalmente, creo que se pueden obtener resultados consistentes
find
al sustituir siempre.
el directorio actual por el directorio actual antes de continuar.fuente
No hay ningún objeto nombrado
foo
en el directorio donde inició la búsqueda relativa.Está en lo cierto al suponer que
gfind
tiene errores cuando informa/tmp/foo
cuando se usa el nombre absoluto como directorio de inicio.Gfind
tiene varias desviaciones del estándar, parece que encontraste otra. Cuando desee una solución compatible más estándar, le recomiendosfind
que sea parte delschilytools
.-name
se aplica a los resultados de búsqueda del directorio. Ninguno de los dos casos que menciona devolverá una entrada de directoriofoo
de unareaddir()
operación.fuente
find --version
: find (GNU findutils) 4.4.2 Copyright (C) 2007 Free Software Foundation, Inc. Licencia GPLv3 +: GNU GPL versión 3 o posterior < gnu.org/licenses/gpl.html >find
(certificado POSIX)gfind
ysfind
; el problema solo existe cuando lo usasgfind
. En Linux,gfind
no se instala con su nombre nativo sino con el nombrefind
.find /tmp/foo -name foo
salida/tmp/foo
. (Cc @York) Este es el comportamiento de OpenBSDfind
, GNUfind
, BusyBoxfind
, Solarisfind
y cualquier otro compatible con POSIXfind
("El primario evaluará como verdadero si el nombre base del nombre del archivo que se examina coincide con el patrón (...)" - cuando el nombre del archivo es uno que se pasa como un operando de ruta, no hayreaddir
llamadas involucradas).