Cómo excluir un directorio en find. mando

1380

Estoy tratando de ejecutar un findcomando para todos los archivos JavaScript, pero ¿cómo excluyo un directorio específico?

Aquí está el findcódigo que estamos usando.

for file in $(find . -name '*.js')
do 
  java -jar config/yuicompressor-2.4.2.jar --type js $file -o $file
done
helion3
fuente
10
¿Cuál es el directorio que necesita excluir?
El arquetipo de Paul
11
Es mejor usarlo find ... | while read -r file .... Además, es mejor aceptar y votar las respuestas.
Pausado hasta nuevo aviso.
mientras lectura es lenta, ya que en es más rápido
mpapis
18
@mpapis mientras se lee correctamente maneja líneas completas con espacios en blanco.
Jean-Philippe Pellet
1
Sólo tiene que ejecutar esto en una carpeta con los archivos con espacios en sus nombres: for file in $(find .); do echo "$file"; done. Los nombres con espacios están divididos, lo que no queremos.
Jean-Philippe Pellet

Respuestas:

1140

Usa el -pruneinterruptor. Por ejemplo, si desea excluir el miscdirectorio, simplemente agregue un -path ./misc -prune -oa su comando de búsqueda:

find . -path ./misc -prune -o -name '*.txt' -print

Aquí hay un ejemplo con múltiples directorios:

find . -type d \( -path dir1 -o -path dir2 -o -path dir3 \) -prune -o -print

Aquí excluimos dir1 , dir2 y dir3 , ya que en las findexpresiones es una acción que actúa según los criterios -path dir1 -o -path dir2 -o -path dir3(si dir1 o dir2 o dir3 ), AND con type -d.

Otra acción es -o print, solo imprimir.

f10bit
fuente
89
Hmm Esto tampoco funciona para mí, ya que incluirá el directorio ignorado "./misc" en la salida.
Theuni
84
@Theuni Probablemente no funcionó para usted porque no agregó una -print(o cualquier otra acción) explícitamente después -name. En ese caso, ambos "lados" de -ola impresión finalizan, mientras que si lo usa -print, solo se imprime ese lado.
Daniel C. Sobral
44
De la página de manual: Because -delete implies -depth, you cannot usefully use -prune and -delete together.Entonces, ¿cómo hago para eliminar con find si deseo excluir directorios específicos de la eliminación?
Jānis Elmeris
15
Para eliminar todo el directorio en sí del uso resultados: find . -not -path "./.git*". El uso en ./dir*lugar de ./dir/*elimina el directorio y los contenidos de la salida.
micahblu
64
Esta pregunta y la confusión en las respuestas es un manifiesto sobre cuán mal coincide la interfaz de usuario de búsqueda con lo que la gente necesita.
Johannes Overmann
1932

Si -pruneno funciona para usted, esto:

find -name "*.js" -not -path "./directory/*"

Advertencia: requiere atravesar todos los directorios no deseados.

Liberarse
fuente
86
Uno de los comentarios en la respuesta aceptada señala el problema. -pruneno excluye el directorio en sí, excluye su contenido, lo que significa que obtendrá una línea no deseada en la salida con el directorio excluido.
GetFree
96
Gran respuesta. Agregaría a esto que puede excluir un directorio en CUALQUIER nivel cambiando el primero .a *. así find -name "*.js" -not -path "*/omitme/*"que omitiría archivos de un directorio llamado "omitme" en cualquier nivel de profundidad.
DeeDee
83
Sin embargo, todavía atraviesa todo el directorio no deseado. Estoy agregando mi propia respuesta. :-)
Daniel C. Sobral
18
Sin embargo, tenga en cuenta que la opción de podar solo no funciona si no la usa -printexplícitamente.
Daniel C. Sobral
39
Sería mejor decir "Esta es una alternativa al uso de -prune". Las respuestas que sugieren -prune claramente no son incorrectas, simplemente no son de la manera que lo harías.
Jimbo
459

Encuentro lo siguiente más fácil de razonar que otras soluciones propuestas:

find build -not \( -path build/external -prune \) -name \*.js
# you can also exclude multiple paths
find build -not \( -path build/external -prune \) -not \( -path build/blog -prune \) -name \*.js

Nota importante: las rutas que escriba después -pathdeben coincidir exactamente con lo que findse imprimiría sin la exclusión. Si esta frase confunde que sólo asegúrese de usar rutas completas en todo el conjunto de comandos de esta manera: . Consulte la nota [1] si desea una mejor comprensión.find /full/path/ -not \( -path /full/path/exclude/this -prune \) ...

En el interior \(y \)es una expresión que se ajuste exactamente build/external (ver nota importante más arriba), y la voluntad, en caso de éxito, evitar el desplazamiento nada por debajo . Esto se agrupa como una sola expresión con el paréntesis escapado, y con el prefijo -notque hará findomitir todo lo que coincida con esa expresión.

Uno podría preguntar si agregar -notno hará que todos los demás archivos estén ocultos por -prunereaparecer, y la respuesta es no. La manera-prune funciona es que todo lo que, una vez alcanzado, los archivos debajo de ese directorio se ignoran permanentemente.

Esto proviene de un caso de uso real, donde necesitaba llamar a yui-compressor en algunos archivos generados por wintersmith, pero omitir otros archivos que deben enviarse tal cual.


Nota [1] : Si desea excluir /tmp/foo/bary ejecuta find como este " find /tmp \(...", debe especificarlo -path /tmp/foo/bar. Si, por otro lado, ejecuta find como este cd /tmp; find . \(..., debe especificarlo -path ./foo/bar.

Daniel C. Sobral
fuente
37
Excelente respuesta, gracias. Esto funciona y es escalable (legible) para múltiples exclusiones. Sois caballeros y eruditos, señor. Gracias por el ejemplo de las exclusiones múltiples
Freedom_Ben
77
Esto no funciona si quiero usar el interruptor -delete:find . -not \( -path ./CVS -prune \) -type f -mtime +100 -delete find: The -delete action atomatically turns on -depth, but -prune does nothing when -depth is in effect. If you want to carry on anyway, just explicitly use the -depth option.
Jānis Elmeris
17
@ Janis Puedes usar en -exec rm -rf {} \;lugar de -delete.
Daniel C. Sobral
11
Al examinar la salida de find, esto es realmente obvio, pero me hizo tropezar. Si usted está buscando en el directorio actual (especificando .como la ruta de búsqueda, o no especifica ninguno en absoluto), lo más probable es que su patrón después de -pathempezar con ./, por ejemplo: find -not \( -path ./.git -prune \) -type f.
Zantier
77
Una variación más precisa (y compatible con POSIX) de este método: find searchdir \! \( -type d \( -path './excludedir/*' -o -path './excludedir2/*' -o -path './excludedir3/*' \) -prune \)seguida de cualquier condición que coincida con lo que está buscando.
Walf
219

Claramente, aquí existe cierta confusión sobre cuál debería ser la sintaxis preferida para omitir un directorio.

Opinión de GNU

To ignore a directory and the files under it, use -prune

Desde la página de manual de encontrar de GNU

Razonamiento

-prunedeja findde descender a un directorio. Solo especificar -not -pathseguirá descendiendo al directorio omitido , pero -not -pathserá falso cada vezfind pruebe cada archivo.

Problemas con -prune

-prune hace lo que está destinado a hacer, pero aún hay algunas cosas que debe tener en cuenta al usarlo.

  1. find imprime el directorio podado.

    • VERDADERO Ese es el comportamiento previsto, simplemente no desciende a él. Para evitar imprimir el directorio por completo, use una sintaxis que lo omita lógicamente.
  2. -prunesolo funciona con -printy no otras acciones.

    • NO ES VERDAD . -prunefunciona con cualquier acción excepto -delete. ¿Por qué no funciona con eliminar? Para -deletetrabajar, find necesita atravesar el directorio en orden DFS, ya -deleteque primero eliminará las hojas, luego los padres de las hojas, etc. Pero para especificar -pruneque tiene sentido, finddebe presionar un directorio y dejar de descender, lo que claramente no tiene sentido con -deptho -deletesobre.

Actuación

Configuré una prueba simple de las tres respuestas más votadas sobre esta pregunta (reemplazada -printpor -exec bash -c 'echo $0' {} \;para mostrar otro ejemplo de acción). Los resultados están abajo

----------------------------------------------
# of files/dirs in level one directories
.performance_test/prune_me     702702    
.performance_test/other        2         
----------------------------------------------

> find ".performance_test" -path ".performance_test/prune_me" -prune -o -exec bash -c 'echo "$0"' {} \;
.performance_test
.performance_test/other
.performance_test/other/foo
  [# of files] 3 [Runtime(ns)] 23513814

> find ".performance_test" -not \( -path ".performance_test/prune_me" -prune \) -exec bash -c 'echo "$0"' {} \;
.performance_test
.performance_test/other
.performance_test/other/foo
  [# of files] 3 [Runtime(ns)] 10670141

> find ".performance_test" -not -path ".performance_test/prune_me*" -exec bash -c 'echo "$0"' {} \;
.performance_test
.performance_test/other
.performance_test/other/foo
  [# of files] 3 [Runtime(ns)] 864843145

Conclusión

Tanto la sintaxis de f10bit y la sintaxis de Daniel C. Sobral tomaron 10-25ms para funcionar en promedio. La sintaxis de GetFree , que no usa -prune, tomó 865 ms. Entonces, sí, este es un ejemplo bastante extremo, pero si le importa el tiempo de ejecución y está haciendo algo remotamente intensivo, debe usar-prune .

Tenga en cuenta que la sintaxis de Daniel C. Sobral fue la mejor de las dos -prunesintaxis; pero, sospecho fuertemente que esto es el resultado de un cierto almacenamiento en caché, ya que cambiar el orden en que se ejecutaron los dos dio como resultado el resultado opuesto, mientras que la versión sin poda siempre fue la más lenta.

Script de prueba

#!/bin/bash

dir='.performance_test'

setup() {
  mkdir "$dir" || exit 1
  mkdir -p "$dir/prune_me/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/w/x/y/z" \
    "$dir/other"

  find "$dir/prune_me" -depth -type d -exec mkdir '{}'/{A..Z} \;
  find "$dir/prune_me" -type d -exec touch '{}'/{1..1000} \;
  touch "$dir/other/foo"
}

cleanup() {
  rm -rf "$dir"
}

stats() {
  for file in "$dir"/*; do
    if [[ -d "$file" ]]; then
      count=$(find "$file" | wc -l)
      printf "%-30s %-10s\n" "$file" "$count"
    fi
  done
}

name1() {
  find "$dir" -path "$dir/prune_me" -prune -o -exec bash -c 'echo "$0"'  {} \;
}

name2() {
  find "$dir" -not \( -path "$dir/prune_me" -prune \) -exec bash -c 'echo "$0"' {} \;
}

name3() {
  find "$dir" -not -path "$dir/prune_me*" -exec bash -c 'echo "$0"' {} \;
}

printf "Setting up test files...\n\n"
setup
echo "----------------------------------------------"
echo "# of files/dirs in level one directories"
stats | sort -k 2 -n -r
echo "----------------------------------------------"

printf "\nRunning performance test...\n\n"

echo \> find \""$dir"\" -path \""$dir/prune_me"\" -prune -o -exec bash -c \'echo \"\$0\"\'  {} \\\;
name1
s=$(date +%s%N)
name1_num=$(name1 | wc -l)
e=$(date +%s%N)
name1_perf=$((e-s))
printf "  [# of files] $name1_num [Runtime(ns)] $name1_perf\n\n"

echo \> find \""$dir"\" -not \\\( -path \""$dir/prune_me"\" -prune \\\) -exec bash -c \'echo \"\$0\"\' {} \\\;
name2
s=$(date +%s%N)
name2_num=$(name2 | wc -l)
e=$(date +%s%N)
name2_perf=$((e-s))
printf "  [# of files] $name2_num [Runtime(ns)] $name2_perf\n\n"

echo \> find \""$dir"\" -not -path \""$dir/prune_me*"\" -exec bash -c \'echo \"\$0\"\' {} \\\;
name3
s=$(date +%s%N)
name3_num=$(name3 | wc -l)
e=$(date +%s%N)
name3_perf=$((e-s))
printf "  [# of files] $name3_num [Runtime(ns)] $name3_perf\n\n"

echo "Cleaning up test files..."
cleanup
Restablecer a monica por favor
fuente
18
Gracias por un muy buen análisis. Con respecto a "Sospecho firmemente que este es el resultado de un poco de almacenamiento en caché", puede ejecutar este comando: sudo sh -c "free && sync && echo 3> / proc / sys / vm / drop_caches && free" para borrar el caché (vea unix. stackexchange.com/questions/87908/… ).
ndemou
Después de algunas pruebas con esos dos -prune, puedo decir que rara vez hay alguna diferencia. Tenga en cuenta que el comando que comience primero se beneficiará del rendimiento de la CPU, el calentamiento posterior de la CPU> la caída del rendimiento causará una desaceleración menor (purgué el caché antes de cada comando como sugerencia de @ndemou)
Huy.PhamNhu
Intente cambiar el número name1() name2() name3()en el script de prueba @BroSlow anterior para cambiar el orden de ejecución y obtener una visión de lo que dije. Sin embargo, en la vida real es imperceptible entre esos dos.
Huy.PhamNhu
Aplausos. Gracias por esta respuesta de calidad.
Stphane
No deberías ser -o, lo que significa o. entonces estás podando en el primer paso y luego olvidaste todo en el siguiente.
mmm
97

Este es el único que funcionó para mí.

find / -name MyFile ! -path '*/Directory/*'

Buscando "MyFile" excluyendo "Directorio". Dar énfasis a las estrellas *.

DimiDak
fuente
13
Este método funciona en macOS mientras que la respuesta aceptada no. Sé que la pregunta original es para Linux.
Xavier Rubio Jansana
55
Tenga en cuenta que puede agregar múltiples ! -path '*/Directory/*'a su comando en sucesión para ignorar múltiples directorios
Aclwitt
Funciona en MacOS pero no en Linux ... confirmado
Marcello de Sales
En un docker containersolo funciona consh -c "find..."
Marcello de Sales
@Marcello de Sales Por supuesto, funciona en Linux.
DimiDak
59

Una opción sería excluir todos los resultados que contienen el nombre del directorio con grep. Por ejemplo:

find . -name '*.js' | grep -v excludeddir
Joshua
fuente
44
Esto hará que su búsqueda sea muy lenta
Dorian
66
Este funcionó para mí, otros (que usan -prune), no.
Andron
77
Lento en grandes resultados, pero útil en conjuntos más pequeños. ¿Pero cómo excluir múltiples directorios usando grep? Por supuesto de esta manera: find . -name '*.js' | grep -v excludeddir | grep -v excludedir2 | grep -v excludedir3pero puede haber alguna manera grep.
Timo Kähkönen
66
Si desea realizar múltiples greps entonces sería mejor escribirlo como expresiones regulares: egrep -v '(dir1|dir2|dir3)'. Sin embargo, en este caso de estudio específico, sería mejor excluir directorios dentro de findsí mismo.
Laurence
1
sí, y no necesita paréntesis y sería mejor usar ^ para asegurarse de que coincida con el nombre del directorio al comienzo de la cadena, por ejemplo: find. -nombre '* .js' | egrep -v "^ \ ./ excludeddir1 | ^ \ ./ excludeddir2"
Sofija
41

Prefiero la -notnotación ... es más legible:

find . -name '*.js' -and -not -path directory
mpapis
fuente
55
Lo siento, no funciona. La página del manual finddice: "Para ignorar un directorio y los archivos que se encuentran debajo, use -prune".
Christian Davén
8
Esto está mal. No impide que find ingrese al directorio y atraviese todos los archivos dentro.
GetFree
find . -iname '*' -and -not -path './somePath'no evita que ingrese a dicho directorio.
Lemmings19
Esto me ayudó con el camino .git find . -iname '*' -not -path './.git/*'
Mark Shust en M.academy
77
@rane: Más específicamente find . -not -path "*/.git*"sería lo que quieres.
Ben
20

Use la opción -prune. Entonces, algo como:

find . -type d -name proc -prune -o -name '*.js'

El '-type d -name proc -prune' solo busca directorios llamados proc para excluir.
El '-o' es un operador 'OR'.

Drew Frezell
fuente
1
Esta es la única solución pura de "encontrar" que funcionó para mí. Los directorios que deseaba excluir NO están inmediatamente debajo del directorio de trabajo actual.
Lambart
55
Sin embargo, agregar -printal final puede mejorar los resultados. find . -type d -name .hg -prune -o -name dataignoró el contenido de los .hgdirectorios (múltiples) , pero enumeró los .hgdirectorios en sí. Con -print, solo enumeraba los directorios de "datos" que estaba buscando.
Lambart el
19

-prunedefinitivamente funciona y es la mejor respuesta porque evita descender al directorio que desea excluir. -not -pathque aún busca el directorio excluido, simplemente no imprime el resultado, lo que podría ser un problema si el directorio excluido está montado en el volumen de la red o no tiene permisos.

La parte difícil es que findes muy particular sobre el orden de los argumentos, por lo que si no los entiende correctamente, es posible que su comando no funcione. El orden de los argumentos es generalmente como tal:

find {path} {options} {action}

{path}: Ponga todos los argumentos relacionados con la ruta primero, como . -path './dir1' -prune -o

{options}: Tengo el mayor éxito al poner -name, -iname, etccomo última opción en este grupo. P.ej-type f -iname '*.js'

{action}: Querrás agregar -printcuando uses-prune

Aquí hay un ejemplo de trabajo:

# setup test
mkdir dir1 dir2 dir3
touch dir1/file.txt; touch dir1/file.js
touch dir2/file.txt; touch dir2/file.js
touch dir3/file.txt; touch dir3/file.js

# search for *.js, exclude dir1
find . -path './dir1' -prune -o -type f -iname '*.js' -print

# search for *.js, exclude dir1 and dir2
find . \( -path './dir1' -o -path './dir2' \) -prune -o -type f -iname '*.js' -print
wisbucky
fuente
16

Este es el formato que utilicé para excluir algunas rutas:

$ find ./ -type f -name "pattern" ! -path "excluded path" ! -path "excluded path"

Usé esto para encontrar todos los archivos que no están en las rutas ". *":

$ find ./ -type f -name "*" ! -path "./.*" ! -path "./*/.*"
usuario1882879
fuente
Intenté esto y todavía desciende a los directorios, por lo que la velocidad definitivamente no mejora.
Br.Bill
10

El enfoque -path -prune también funciona con comodines en la ruta. Aquí hay una declaración find que encontrará los directorios para un servidor git que sirve a múltiples repositorios git que dejan fuera los directorios internos de git:

find . -type d \
   -not \( -path */objects -prune \) \
   -not \( -path */branches -prune \) \
   -not \( -path */refs -prune \) \
   -not \( -path */logs -prune \) \
   -not \( -path */.git -prune \) \
   -not \( -path */info -prune \) \
   -not \( -path */hooks -prune \)  
Wolfgang Fahl
fuente
9

Para excluir múltiples directorios:

find . -name '*.js' -not \( -path "./dir1" -o -path "./dir2/*" \)

Para agregar directorios, agregue -o -path "./dirname/*":

find . -name '*.js' -not \( -path "./dir1" -o -path "./dir2/*" -o -path "./dir3/*"\)

Pero tal vez debería usar una expresión regular , si hay muchos directorios para excluir.

JBENOIT
fuente
9

Hay muchas buenas respuestas, solo me llevó un tiempo entender para qué era cada elemento del comando y la lógica detrás de él.

find . -path ./misc -prune -o -name '*.txt' -print

find comenzará a buscar archivos y directorios en el directorio actual, de ahí el find . .

La -oopción representa un OR lógico y separa las dos partes del comando:

[ -path ./misc -prune ] OR [ -name '*.txt' -print ]

Cualquier directorio o archivo que no sea el directorio ./misc no pasará la primera prueba -path ./misc. Pero serán probados contra la segunda expresión. Si su nombre corresponde al patrón *.txtque imprimen, debido a la-print opción.

Cuando find alcanza el directorio ./misc, este directorio solo satisface la primera expresión. Entonces -prunese le aplicará la opción. Le dice al comando find que no explore ese directorio. Por lo tanto, cualquier archivo o directorio en ./misc ni siquiera será explorado por find, no se probará con la segunda parte de la expresión y no se imprimirá.

Istopopoki
fuente
Todos tienen una solución, pero la suya lo explicó mejor. Fui inflexible para que se usara -name primero en lugar de -path. Su explicación fue adecuada para llegar a lo que quería. encontrar . -name "* .txt" -print -o -path ./misc -prune
Vendetta V
7

Para una solución de trabajo (probado en Ubuntu 12.04 (Precise Pangolin)) ...

find ! -path "dir1" -iname "*.mp3"

buscará archivos MP3 en la carpeta y subcarpetas actuales, excepto en la subcarpeta dir1.

Utilizar:

find ! -path "dir1" ! -path "dir2" -iname "*.mp3"

... para excluir dir1 Y dir2

james dupin
fuente
No funciona para mi Tampoco ninguna de las respuestas anteriores. Sombrero rojo.
Tharpa
6

un buen truco para evitar imprimir los directorios podados es usar -print(funciona -exectambién) después del lado derecho del -orafter -prune. Por ejemplo, ...

find . -path "*/.*" -prune -or -iname "*.j2"

imprimirá la ruta de todos los archivos debajo del directorio actual con la extensión '.j2 ", omitiendo todos los directorios ocultos. Neat. Pero también imprimirá la impresión de la ruta completa de cada directorio que se omite, como se indicó anteriormente. Sin embargo, el siguiente no, ...

find . -path "*/.*" -prune -or -iname "*.j2" -print

porque lógicamente hay un oculto -anddespués del -inameoperador y antes de la impresión. Esto lo une a la parte derecha de la -orcláusula debido al orden booleano de operaciones y asociatividad. Pero los documentos dicen que hay un oculto -printsi no -print0está especificado (o alguno de sus primos ... , etc.). Entonces, ¿por qué no está la parte izquierda de la -orimpresión? Aparentemente (y no entendí esto desde mi primera lectura de la página del manual), eso es cierto si no hay -print-o -execEN CUALQUIER LUGAR, en cuyo caso, -print se rocía lógicamente para que todo se imprima. Si incluso UNOprint operación estilo expresada en alguna cláusula, todos esos lógicos ocultos desaparecen y obtienes solo lo que especificas. Ahora, francamente, podría haberlo preferido al revés, pero luegofind operador con solo operadores descriptivos aparentemente no haría nada, así que supongo que tiene sentido. Como se mencionó anteriormente, todo esto también funciona -exec, por lo que a continuación se ofrece una ls -lalista completa de cada archivo con la extensión deseada, pero no se enumera el primer nivel de cada directorio oculto, ...

find . -path "*/.*" -prune -or -iname "*.j2" -exec ls -la -- {} +

Para mí (y para otros en este hilo), la findsintaxis se vuelve bastante barroca con bastante rapidez, por lo que siempre agrego parens para asegurarme de saber qué se une a qué, por lo que generalmente creo una macro para la capacidad de escritura y formulo todas las declaraciones como. ..

find . \( \( ... description of stuff to avoid ... \) -prune \) -or \
\( ... description of stuff I want to find ... [ -exec or -print] \)

Es difícil equivocarse configurando el mundo en dos partes de esta manera. Espero que esto ayude, aunque parece poco probable que alguien lea la respuesta número 30 y la vote, pero uno puede esperar. :-)

cicollinas
fuente
5

Puede usar la opción de podar para lograr esto. Como en por ejemplo:

find ./ -path ./beta/* -prune -o -iname example.com -print

O la opción inversa grep "grep -v":

find -iname example.com | grep -v beta

Puede encontrar instrucciones detalladas y ejemplos en el comando de búsqueda de Linux para excluir directorios de la búsqueda .

Siju V
fuente
La solución grep es la única que excluye todos los directorios con el mismo nombre. Cuando se trata de excluir "node_modules", eso es bastante útil.
bmacnaughton
3
@bmacnaughton - ¡no es cierto! Vine aquí específicamente para excluir "node_modules" y después de leer muchas respuestas precisas me decidí por find . -type f -print -o -path "*/node_modules" -prune... usando el comodín esto omite "node_modules" en cualquier nivel; el uso -printen la primera alternativa -type f -printsolo imprime esa parte, por lo que los directorios "node_modules" no están en la lista. (También se puede invertir: find . -path "*/node_modules" -prune -o -type f -print)
Stephen P
¿Qué está haciendo * / allí? ¿Cuál es el archivo exacto que desea excluir? ¿Lo está utilizando como comodín?
Siju V
1
@StephenP, gracias por señalar esto; Aprendí la diferencia entre usar ./node_modulesy */node_modulesde él. Para mi caso, donde node_modulessolo existe en el directorio en el que comienzo la búsqueda (y debajo de ese node_modulesdirectorio), puedo usarlo find . -type f -print -o -path "./node_modules" -prune porque no habrá un node_modulesdirectorio en ningún otro directorio.
bmacnaughton
1
@SijuV: en el directorio donde estaba buscando había un node_modulessubdirectorio, pero también había subdirectorios que tenían sus propios node_modules ... utilizando ./node_modulescoincidencias solo con el subdirectorio node_modulesbajo el directorio actual .y lo poda; usando */node_modulescoincidencias y poda el directorio a cualquier profundidad, ya que *as como un globo coincide con cualquier prefijo de ruta principal, como ./test5/main/node_modulesno solo el ./prefijo. El *es un comodín, pero como un globo no como una expresión regular.
Stephen P
5
find . -name '*.js' -\! -name 'glob-for-excluded-dir' -prune
El arquetipo de Pablo
fuente
No puedo hacer que este funcione. find ~/Projects -name '*.js' -\! -name 'node_modules' -prunesigue apareciendo archivos node_modulesen su camino
mpen
1
@mpen, De stackoverflow.com/questions/4210042/… , aprendí que la sintaxis que deseas es find ~/Projects -path ~/Projects/node_modules -prune -o -name '*.js' -print. El nombre de esa ruta debe coincidir exactamente con lo que find imprimiría si fuera a imprimir el directorio.
PatS
4
find -name '*.js' -not -path './node_modules/*' -not -path './vendor/*'

parece funcionar igual que

find -name '*.js' -not \( -path './node_modules/*' -o -path './vendor/*' \)

y es más fácil de recordar IMO.

Funkodebat
fuente
4

TLDR: comprenda sus directorios raíz y adapte su búsqueda desde allí, utilizando la -path <excluded_path> -prune -oopción No incluya un final/ al final de la ruta excluida.

Ejemplo:

find / -path /mnt -prune -o -name "*libname-server-2.a*" -print


Para utilizar de manera efectiva find, creo que es imperativo tener una buena comprensión de la estructura de directorios de su sistema de archivos. En la computadora de mi casa tengo discos duros de TB múltiple, con aproximadamente la mitad de ese contenido respaldado usando rsnapshot(es decir, rsync). Aunque se realiza una copia de seguridad en una unidad físicamente independiente (duplicada), está montada en el /directorio raíz ( ) de mi sistema /mnt/Backups/rsnapshot_backups/:

/mnt/Backups/
└── rsnapshot_backups/
    ├── hourly.0/
    ├── hourly.1/
    ├── ...
    ├── daily.0/
    ├── daily.1/
    ├── ...
    ├── weekly.0/
    ├── weekly.1/
    ├── ...
    ├── monthly.0/
    ├── monthly.1/
    └── ...

El /mnt/Backups/rsnapshot_backups/directorio actualmente ocupa ~ 2.9 TB, con ~ 60 millones de archivos y carpetas; simplemente atravesar esos contenidos lleva tiempo:

## As sudo (#), to avoid numerous "Permission denied" warnings:

time find /mnt/Backups/rsnapshot_backups | wc -l
60314138    ## 60.3M files, folders
34:07.30    ## 34 min

time du /mnt/Backups/rsnapshot_backups -d 0
3112240160  /mnt/Backups/rsnapshot_backups    ## 3.1 TB
33:51.88    ## 34 min

time rsnapshot du    ## << more accurate re: rsnapshot footprint
2.9T    /mnt/Backups/rsnapshot_backups/hourly.0/
4.1G    /mnt/Backups/rsnapshot_backups/hourly.1/
...
4.7G    /mnt/Backups/rsnapshot_backups/weekly.3/
2.9T    total    ## 2.9 TB, per sudo rsnapshot du (more accurate)
2:34:54          ## 2 hr 35 min

Por lo tanto, cada vez que necesito buscar un archivo en mi / partición (raíz), necesito tratar (evitar si es posible) atravesar mi partición de copias de seguridad.


EJEMPLOS

Entre los abordados sugeridos de diversas maneras en este hilo ( Cómo excluir un directorio en el comando find. ), Encuentro que las búsquedas que usan la respuesta aceptada son mucho más rápidas, con advertencias.

Solución 1

Digamos que quiero encontrar el archivo del sistema libname-server-2.a, pero no quiero buscar entre mis rsnapshotcopias de seguridad. Para encontrar rápidamente un archivo del sistema, use la ruta de exclusión /mnt(es decir, use /mnt, not /mnt/, or /mnt/Backups, or ...):

## As sudo (#), to avoid numerous "Permission denied" warnings:

time find / -path /mnt -prune -o -name "*libname-server-2.a*" -print
/usr/lib/libname-server-2.a
real    0m8.644s              ## 8.6 sec  <<< NOTE!
user    0m1.669s
 sys    0m2.466s

## As regular user (victoria); I also use an alternate timing mechanism, as
## here I am using 2>/dev/null to suppress "Permission denied" warnings:

$ START="$(date +"%s")" && find 2>/dev/null / -path /mnt -prune -o \
    -name "*libname-server-2.a*" -print; END="$(date +"%s")"; \
    TIME="$((END - START))"; printf 'find command took %s sec\n' "$TIME"
/usr/lib/libname-server-2.a
find command took 3 sec     ## ~3 sec  <<< NOTE!

... encuentra ese archivo en solo unos segundos, mientras que esto toma mucho más tiempo (parece repetirse a través de todos los directorios "excluidos"):

## As sudo (#), to avoid numerous "Permission denied" warnings:

time find / -path /mnt/ -prune -o -name "*libname-server-2.a*" -print
find: warning: -path /mnt/ will not match anything because it ends with /.
/usr/lib/libname-server-2.a
real    33m10.658s            ## 33 min 11 sec (~231-663x slower!)
user    1m43.142s
 sys    2m22.666s

## As regular user (victoria); I also use an alternate timing mechanism, as
## here I am using 2>/dev/null to suppress "Permission denied" warnings:

$ START="$(date +"%s")" && find 2>/dev/null / -path /mnt/ -prune -o \
    -name "*libname-server-2.a*" -print; END="$(date +"%s")"; \
    TIME="$((END - START))"; printf 'find command took %s sec\n' "$TIME"
/usr/lib/libname-server-2.a
find command took 1775 sec    ## 29.6 min

Solución 2

La otra solución ofrecida en este hilo ( SO # 4210042 ) también funciona mal:

## As sudo (#), to avoid numerous "Permission denied" warnings:

time find / -name "*libname-server-2.a*" -not -path "/mnt"
/usr/lib/libname-server-2.a
real    33m37.911s            ## 33 min 38 sec (~235x slower)
user    1m45.134s
 sys    2m31.846s

time find / -name "*libname-server-2.a*" -not -path "/mnt/*"
/usr/lib/libname-server-2.a
real    33m11.208s            ## 33 min 11 sec
user    1m22.185s
 sys    2m29.962s

RESUMEN | CONCLUSIONES

Utilice el enfoque ilustrado en la " Solución 1 "

find / -path /mnt -prune -o -name "*libname-server-2.a*" -print

es decir

... -path <excluded_path> -prune -o ...

teniendo en cuenta que cada vez que agrega el final /a la ruta excluida, el findcomando ingresa recursivamente (todos esos) /mnt/*directorios, lo que en mi caso, debido a los /mnt/Backups/rsnapshot_backups/*subdirectorios, ¡también incluye ~ 2.9 TB de archivos para buscar! Al no agregar un final, /la búsqueda debe completarse casi de inmediato (en segundos).

Del mismo modo, la "Solución 2" ( ... -not -path <exclude path> ...) parece buscar recursivamente a través de los directorios excluidos, no devuelve coincidencias excluidas, pero consume innecesariamente ese tiempo de búsqueda.


Buscando dentro de esos rsnapshot copias de seguridad:

Para encontrar un archivo en una de mis rsnapshotcopias de seguridad por hora / día / semana / mes ):

$ START="$(date +"%s")" && find 2>/dev/null /mnt/Backups/rsnapshot_backups/daily.0 -name '*04t8ugijrlkj.jpg'; END="$(date +"%s")"; TIME="$((END - START))"; printf 'find command took %s sec\n' "$TIME"
/mnt/Backups/rsnapshot_backups/daily.0/snapshot_root/mnt/Vancouver/temp/04t8ugijrlkj.jpg
find command took 312 sec   ## 5.2 minutes: despite apparent rsnapshot size
                            ## (~4 GB), it is in fact searching through ~2.9 TB)

Excluyendo un directorio anidado:

Aquí, quiero excluir un directorio anidado, por ejemplo, /mnt/Vancouver/projects/ie/claws/data/*al buscar desde /mnt/Vancouver/projects/:

$ time find . -iname '*test_file*'
./ie/claws/data/test_file
./ie/claws/test_file
0:01.97

$ time find . -path '*/data' -prune -o -iname '*test_file*' -print
./ie/claws/test_file
0:00.07

Aparte: Agregar -printal final del comando suprime la impresión del directorio excluido:

$ find / -path /mnt -prune -o -name "*libname-server-2.a*"
/mnt
/usr/lib/libname-server-2.a

$ find / -path /mnt -prune -o -name "*libname-server-2.a*" -print
/usr/lib/libname-server-2.a
Victoria Stuart
fuente
No es el tamaño de los archivos lo que disminuye find, es el número de entradas de directorio que debe examinar. Por lo tanto, es mucho peor si tiene muchos, muchos archivos pequeños (¡especialmente si están todos vinculados de forma múltiple!) Que si solo tiene un puñado de archivos de varios gigabytes.
Toby Speight
@TobySpeight: buen punto. Mencioné el tamaño del espacio de búsqueda para indicar la escala, que también contiene muchos archivos. Una búsqueda rápida de root (/) con sudo ls -R / | wc -lindica ~ 76.5M de archivos (la mayoría de los cuales están respaldados excepto los archivos de sistema "no configurados"); /mnt/Vancouver/con ls -R | wc -lindica ~ 2.35M de archivos; /home/victoria/contiene 0.668M de archivos.
Victoria Stuart
4

También puede usar expresiones regulares para incluir / excluir algunos archivos / directorios de su búsqueda usando algo como esto:

find . -regextype posix-egrep -regex ".*\.(js|vue|s?css|php|html|json)$" -and -not -regex ".*/(node_modules|vendor)/.*" 

Esto solo le dará todos los archivos js, vue, css, etc. pero excluyendo todos los archivos en las carpetas node_modulesy vendor.

supersan
fuente
3

Estaba usando findpara proporcionar una lista de archivos xgettexty quería omitir un directorio específico y sus contenidos. Intenté muchas permutaciones -pathcombinadas con, -prunepero no pude excluir completamente el directorio que quería que desapareciera.

Aunque pude ignorar el contenido del directorio que quería ignorar, findluego devolví el directorio como uno de los resultados, lo que provocó xgettextun bloqueo como resultado (no acepta directorios; solo archivos).

Mi solución fue simplemente usar grep -vpara omitir el directorio que no quería en los resultados:

find /project/directory -iname '*.php' -or -iname '*.phtml' | grep -iv '/some/directory' | xargs xgettext

Si hay o no un argumento para findque funcione al 100%, no puedo decirlo con certeza. Usar grepera una solución rápida y fácil después de un dolor de cabeza.

Lemmings19
fuente
3

Ninguna de las respuestas anteriores es buena en Ubuntu. Prueba esto:

find . ! -path "*/test/*" -type f -name "*.js" ! -name "*-min-*" ! -name "*console*"

He encontrado esto aqui

sixro
fuente
No veo ninguna razón por la cual cualquiera de las respuestas con más de 100 puntos no debería funcionar en Ubuntu.
Axel Beckert
mmm vamos a ver? tal vez porque los probé todos?
sixro
find es en todas partes la misma implementación en todas las distribuciones de Linux: la del Proyecto GNU. La única diferencia podría ser las versiones. Pero los cambios en la última década no fueron tan invasivos, excepto quizás por la correspondencia de permisos.
Axel Beckert
3

Esto es adecuado para mí en una Mac:

find . -name *.php -or -path "./vendor" -prune -or -path "./app/cache" -prune

Excluirá vendory dirigirá el app/cachenombre de búsqueda con sufijo php.

jiahut
fuente
Mejor ponga comillas simples alrededor de '* .php' o no encontrará lo que está buscando.
Br
3

Para aquellos de ustedes en las versiones anteriores de UNIX que no pueden utilizar -path o -no

Probado en SunOS 5.10 bash 3.2 y SunOS 5.11 bash 4.4

find . -type f -name "*" -o -type d -name "*excluded_directory*" -prune -type f
JaredTS486
fuente
Podría pasar más que el directorio especificado.
MUY Bélgica
2

cómo-usar-podar-opción-de-encontrar-en-sh es una excelente respuesta de Laurence Gonsalves sobre cómo -prunefunciona.

Y aquí está la solución genérica:

find /path/to/search                    \
  -type d                               \
    \( -path /path/to/search/exclude_me \
       -o                               \
       -name exclude_me_too_anywhere    \
     \)                                 \
    -prune                              \
  -o                                    \
  -type f -name '*\.js' -print

Para evitar escribir /path/to/seach/varias veces, envuélvala finden un pushd .. popdpar.

pushd /path/to/search;                  \
find .                                  \
  -type d                               \
    \( -path ./exclude_me               \
       -o                               \
       -name exclude_me_too_anywhere    \
     \)                                 \
    -prune                              \
  -o                                    \
  -type f -name '*\.js' -print;         \
 popd
go2null
fuente
1
De stackoverflow.com/questions/4210042/… , aprendí que la sintaxis utilizada para el -pathdebe coincidir con el nombre que find se imprimiría si se imprimiera el directorio, por ejemplo find . -path ./.git -prune -o -print, o find $HOME/foo -path $HOME/foo/.git -prune -o -print algunas de las respuestas solo dicen -path somedircuál es desafortunadamente No es lo suficientemente exacto para ser útil.
PatS
2

Por lo que necesitaba, funcionó así, encontrando landscape.jpgen todos los servidores comenzando desde la raíz y excluyendo la búsqueda en el /vardirectorio:

find / -maxdepth 1 -type d | grep -v /var | xargs -I '{}' find '{}' -name landscape.jpg

find / -maxdepth 1 -type denumera todos los d irectories en/

grep -v /var excluye `/ var 'de la lista

xargs -I '{}' find '{}' -name landscape.jpgejecutar cualquier comando, como findcon cada directorio / resultado de la lista

adrianTNT
fuente
Espera un segundo, /no está excluido todavía. Usted puede necesitar sed 1d.
Simba
2

Los siguientes comandos funcionan:

find . -path ./.git -prune -o -print

Si tiene un problema con find, use la -D treeopción para ver la información del análisis de expresión.

find -D tree . -path ./.git -prune -o -print

O el -D all, para ver toda la información de ejecución.

find -D all . -path ./.git -prune -o -print
EIIPII
fuente
1

Encontré el nombre de las funciones en los archivos de fuentes de C excluir * .o y excluir * .swp y excluir (no un archivo normal) y excluir la salida del directorio con este comando:

find .  \( ! -path "./output/*" \) -a \( -type f \) -a \( ! -name '*.o' \) -a \( ! -name '*.swp' \) | xargs grep -n soc_attach
Ivan Ivanovich
fuente
1

Mejor usar la execacción que el forbucle:

find . -path "./dirtoexclude" -prune \
    -o -exec java -jar config/yuicompressor-2.4.2.jar --type js '{}' -o '{}' \;

Se exec ... '{}' ... '{}' \;ejecutará una vez por cada archivo coincidente, reemplazando las llaves'{}' con el nombre del archivo actual.

Tenga en cuenta que los corchetes están entre comillas simples para protegerlos de la interpretación como puntuación de script de shell * .


Notas

* Desde la sección de EJEMPLOS de la find (GNU findutils) 4.4.2página del manual

Alberto
fuente
1
Pregunta muy antigua, pero aún con margen de mejora. Lo encontré por casualidad tratando de resolver un problema similar, y ninguna de las respuestas fue satisfactoria.
Alberto
Uso la execacción a menudo y me resulta muy útil. Normalmente agrego comillas entre {}si hay espacios en las rutas de archivo que da "{}".
Ludovic Kuty
@lkuty Estaba a punto de editar mi publicación para reflejar su comentario, pero después de una prueba rápida (sin citas, {}funciona para archivos con espacios en blanco en sus nombres) y una mirada a las páginas del manual, parece que las citas solo son necesarias para evitar que se malinterpreten como puntuación de script de shell. En este caso, usaría una cita simple:'{}'
Alberto
Creo que tuve que usarlo para hacer cpo mvo rm. Lo comprobaré
Ludovic Kuty
1

Intenté el comando anterior, pero ninguno de los que usan "-prune" funciona para mí. Finalmente probé esto con el siguiente comando:

find . \( -name "*" \) -prune -a ! -name "directory"
Jolly Liu
fuente