recursive files comando linux shell find

linux - files - man find



Cómo excluir un directorio en encontrar. mando (30)

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

Aquí está el código de find que estamos usando.

for file in $(find . -name ''*.js'') do java -jar config/yuicompressor-2.4.2.jar --type js $file -o $file done


Claramente, existe cierta confusión en cuanto a 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 GNU find.

Razonamiento

-prune detiene find de descender a un directorio. Simplemente especificando -not -path seguirá descendiendo en el directorio omitido , pero -not -path será falsa cada vez que find pruebas en cada archivo.

Problemas con la -prune

-prune hace lo que se pretende, pero todavía hay algunas cosas que debes cuidar cuando lo -prune .

  1. find imprime el directorio podado.

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

    • No es cierto -prune funciona con cualquier acción excepto -delete . ¿Por qué no funciona con eliminar? Para que -delete funcione, encontrar necesita atravesar el directorio en el orden DFS, ya que -delete primero eliminará las hojas, luego los padres de las hojas, etc. Pero para especificar -prune para que tenga sentido, find necesidades para golpear un directorio y deje de descenderlo, lo que claramente no tiene sentido con -depth o -delete on.

Actuación

Configuré una prueba simple de las tres respuestas con los mejores votos en esta pregunta (reemplazé -print con -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 como la de Daniel C. Sobral tomaron de 10 a 25 ms en promedio. La sintaxis de GetFree , que no usa -prune , tomó 865ms. Entonces, sí, este es un ejemplo bastante extremo, pero si te importa el tiempo de ejecución y estás haciendo algo de forma remota intensiva, debes usar -prune .

Tenga en cuenta que la sintaxis de Daniel C. Sobral fue la mejor de las dos sintaxis de las -prune ; pero, sospecho fuertemente que esto es el resultado de cierto almacenamiento en caché, ya que cambiar el orden en el que se ejecutaron los dos resultó en el resultado opuesto, mientras que la versión sin podar 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


El enfoque -path -prune también funciona con comodines en la ruta. Aquí hay una declaración de búsqueda que encontrará los directorios para un servidor git que sirve múltiples repositorios de git sin incluir 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 /)


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

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


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

find build -not /( -path build/external -prune /) -name /*.js

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.

Inside /( y /) es una expresión que coincidirá exactamente con build/external ( no coincidirá si find ./build , por ejemplo, debe cambiarlo a ./build/external en ese caso), y En el éxito, evitará atravesar cualquier cosa a continuación . Luego se agrupa como una sola expresión con el paréntesis de escape, y tiene el prefijo -not que hará que la find omita todo lo que coincidió con esa expresión.

Uno podría preguntar si agregar -not no hará que todos los demás archivos ocultos por -prune reaparecer, y la respuesta es no. La forma en que funciona -prune es que todo lo que, una vez que se alcanza, los archivos debajo de ese directorio se ignoran permanentemente.

Eso también es fácil de expandir para agregar exclusiones adicionales. Por ejemplo:

find build -not /( -path build/external -prune /) -not /( -path build/blog -prune /) -name /*.js


Estaba utilizando find para proporcionar una lista de archivos para xgettext , y quería omitir un directorio específico y su contenido. -path muchas permutaciones de -path combinadas con -prune pero no -prune excluir completamente el directorio que quería que se fuera.

Aunque pude ignorar el contenido del directorio que quería ignorar, find luego devolvió el directorio como uno de los resultados, lo que provocó que xgettext bloquee como resultado (no acepta directorios; solo archivos).

Mi solución fue simplemente usar grep -v para 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 find que funcionará al 100%, no puedo decirlo con certeza. Usar grep fue una solución rápida y fácil después de un dolor de cabeza.


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

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

Buscando "NameOfFile" excluyendo "Directory". Dar énfasis a las estrellas *.


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 "./*/.*"


Esto es adecuado para mí en una Mac:

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

app/cache directorio del vendor y de la app/cache para el nombre de búsqueda que tiene el sufijo php .


Esto funciona porque find TESTS los archivos para el patrón " * foo * ":

find ! -path "dir1" ! -path "dir2" -name "*foo*"

pero NO funciona si no usa un patrón (la find no PRUEBA el archivo). Por lo tanto, find no hace uso de sus valores anteriores evaluados " true " y " false ". Ejemplo para no trabajar caso de uso con notación anterior:

find ! -path "dir1" ! -path "dir2" -type f

No hay ninguna prueba de find ! Por lo tanto, si necesita encontrar archivos sin ninguna coincidencia de patrones, use la tecla -prune. Además, el uso de poda es siempre más rápido, mientras que realmente salta los directorios en lugar de hacerlo o mejor no. Entonces en ese caso usa algo como:

find dir -not /( -path "dir1" -prune /) -not /( -path "dir2" -prune /) -type f

o:

find dir -not /( -path "dir1" -o -path "dir2" -prune /) -type f

Saludos


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

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

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

La opción -o 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 -path ./misc prueba -path ./misc . Pero serán probados contra la segunda expresión. Si su nombre corresponde al patrón *.txt se imprimen, debido a la opción -print .

Cuando find llega al directorio ./misc, este directorio solo satisface la primera expresión. Así que la opción -prune se aplicará a ella. Le dice al comando de búsqueda que no explore ese directorio. Por lo tanto, cualquier archivo o directorio en ./misc ni siquiera será explorado por find, no se probará contra la segunda parte de la expresión y no se imprimirá.


He encontrado las sugerencias en esta página y muchas otras páginas simplemente no funcionan en mi sistema Mac OS X. Sin embargo, he encontrado una variación que funciona para mí.

La gran idea es buscar en Macintosh HD, pero evite atravesar todos los volúmenes externos, que son en su mayoría copias de seguridad de Time Machine, copias de seguridad de imágenes, recursos compartidos montados y archivos, pero sin tener que desmontarlos todos, lo que a menudo no es práctico.

Aquí está mi script de trabajo, que he llamado "findit".

#!/usr/bin/env bash # inspired by http://.com/questions/4210042/exclude-directory-from-find-command Danile C. Sobral # using special syntax to avoid traversing. # However, logic is refactored because the Sobral version still traverses # everything on my system echo ============================ echo find - from cwd, omitting external volumes date echo Enter sudo password if requested sudo find . -not /( / -path ./Volumes/Archive -prune -o / -path ./Volumes/Boot/ OS/ X -prune -o / -path ./Volumes/C / -path ./Volumes/Data -prune -o / -path ./Volumes/jas -prune -o / -path ./Volumes/Recovery/ HD -prune -o / -path ./Volumes/Time/ Machine/ Backups -prune -o / -path ./Volumes/SuperDuper/ Image -prune -o / -path ./Volumes/userland -prune / /) -name "$1" -print date echo ============================ iMac2:~ jas$

Las diversas rutas tienen que ver con volúmenes de archivo externos, Time Machine, máquinas virtuales, otros servidores montados, etc. Algunos de los nombres de volúmenes tienen espacios en ellos.

Una buena ejecución de prueba es "findit index.php", porque ese archivo se produce en muchos lugares de mi sistema. Con este script, demora unos 10 minutos buscar el disco duro principal. Sin esas exclusiones, lleva muchas horas.


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

find . /( -name "*" /) -prune -a ! -name "directory"


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 here


Para aquellos de ustedes en versiones anteriores de UNIX que no pueden usar -path o -not

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


Para excluir directorios múltiples:

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.


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

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

find / -maxdepth 1 -type d enumera todos los irectorios en /

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

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


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

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

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

Utilizar:

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

... excluir dir1 y dir2


Para usuarios de FreeBSD :

find . -name ''*.js'' -not -path ''*exclude/this/dir*''


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

find . -name ''*.js'' -and -not -path directory


Puede utilizar 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 Linux. El comando de búsqueda excluye directorios de la búsqueda .


Si -prune no funciona para usted, esto:

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


Si los directorios de búsqueda tienen patrón (en mi caso la mayoría de las veces); Simplemente puedes hacerlo como abajo:

find ./n* -name "*.tcl"

En el ejemplo anterior; Busca en todos los subdirectorios comenzando con "n".


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


Utilice el modificador de poda, por ejemplo, si desea excluir el directorio misc , simplemente agregue una -path ./misc -prune -o a su comando de búsqueda:

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

Aquí hay un ejemplo con varios directorios:

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

Aquí excluimos dir1, dir2 y dir3, ya que en find expresiones es una acción que actúa en los criterios -path dir1 -o -path dir2 -o -path dir3 (si es dir1 o dir2 o dir3), ANDed con type -d . Otra acción es -o print , solo imprimir.


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

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

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


Utilice mejor la acción exec que el bucle for :

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

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

Observe que las llaves están entre comillas simples para protegerlas de la interpretación como puntuación de script de shell * .

Notas

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


-prune definitivamente funciona y es la mejor respuesta porque evita descender a la dir que desea excluir. -not -path que aún busca en 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 el find es 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 primero todos los argumentos relacionados con la ruta, como . -path ''./dir1'' -prune -o . -path ''./dir1'' -prune -o

{options} : Tengo el mayor éxito al poner -name, -iname, etc como la última opción en este grupo. Por ejemplo, -type f -iname ''*.js''

{action} : querrás agregar -print cuando -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


how-to-use-prune-option-of-find-in-sh es una excelente respuesta de Laurence Gonsalves sobre cómo funciona la -prune .

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, envuelva la find en un par pushd .. popd .

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


find . -name ''*.js'' -/! -name ''glob-for-excluded-dir'' -prune


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.