Use el comando buscar pero excluya archivos en dos directorios


86

Quiero buscar archivos que terminen con _peaks.bed, pero excluir archivos en las carpetas tmpy scripts.

Mi comando es así:

 find . -type f \( -name "*_peaks.bed" ! -name "*tmp*" ! -name "*scripts*" \)

Pero no funcionó. Los archivos tmpy la scriptcarpeta se seguirán mostrando.

¿Alguien tiene ideas sobre esto?

Respuestas:


189

Así es como puede especificar eso con find:

find . -type f -name "*_peaks.bed" ! -path "./tmp/*" ! -path "./scripts/*"

Explicación:

  • find . - Iniciar la búsqueda desde el directorio de trabajo actual (de forma recursiva de forma predeterminada)
  • -type f- Especifique findque solo desea archivos en los resultados
  • -name "*_peaks.bed" - Busque archivos cuyo nombre termine en _peaks.bed
  • ! -path "./tmp/*" - Excluir todos los resultados cuya ruta comience con ./tmp/
  • ! -path "./scripts/*" - También excluir todos los resultados cuya ruta comience con ./scripts/

Prueba de la solución:

$ mkdir a b c d e
$ touch a/1 b/2 c/3 d/4 e/5 e/a e/b
$ find . -type f ! -path "./a/*" ! -path "./b/*"

./d/4
./c/3
./e/a
./e/b
./e/5

Estuviste bastante cerca, la -nameopción solo considera el nombre de base, donde as -pathconsidera la ruta completa =)


Buen trabajo. Sin embargo, olvidó una de las cosas que quería el OP, encontrar archivos que terminen en _peaks.bed.
— alex

2
Esto usa una serie de extensiones en GNU find, pero dado que la pregunta está etiquetada como Linux, eso no es un problema. Buena respuesta.
— Jonathan Leffler

1
Una nota breve: si lo usa .en el indicador de búsqueda inicial, debe usarlo en cada ruta que excluya. La coincidencia de rutas es bastante estricta, no realiza búsquedas difusas. Entonces, si lo usas, find / -type f -name *.bed" ! -path "./tmp/"no va a funcionar. necesitas tener ! -path "/tmp"que hacerlo feliz.
— peelman

3
Importante tener en cuenta que el * es importante. $ ! -path "./directory/*"
— Thomas Bennett

3
Según las páginas del manual: "Para ignorar un árbol de directorios completo, utilice en -prunelugar de comprobar todos los archivos del árbol". Si sus directorios excluidos son muy profundos o tienen toneladas de archivos y le importa el rendimiento, utilice la -pruneopción en su lugar.
— jueves

8

Aquí hay una forma en que puede hacerlo ...

find . -type f -name "*_peaks.bed" | egrep -v "^(./tmp/|./scripts/)"

2
Esto tiene el mérito de trabajar con cualquier versión de findGNU, y no solo con GNU find. Sin embargo, la pregunta está etiquetada como Linux, por lo que no es crítica.
— Jonathan Leffler

2

Utilizar

find \( -path "./tmp" -o -path "./scripts" \) -prune -o  -name "*_peaks.bed" -print

o

find \( -path "./tmp" -o -path "./scripts" \) -prune -false -o  -name "*_peaks.bed"

o

find \( -path "./tmp" -path "./scripts" \) ! -prune -o  -name "*_peaks.bed"

El orden es importante. Evalúa de izquierda a derecha. Comience siempre con la exclusión del camino.

Explicación

No utilice -not(o !) para excluir todo el directorio. Utilice -prune. Como se explica en el manual:

−prune    The primary shall always evaluate as  true;  it
          shall  cause  find  not  to descend the current
          pathname if it is a directory.  If  the  −depth
          primary  is specified, the −prune primary shall
          have no effect.

y en el manual de búsqueda de GNU:

-path pattern
              [...]
              To ignore  a  whole
              directory  tree,  use  -prune rather than checking
              every file in the tree.

De hecho, si usa -not -path "./pathname", find evaluará la expresión para cada nodo debajo "./pathname".

Las expresiones de búsqueda son solo evaluación de condiciones.

  • \( \)- Operación de grupos (puede usar -path "./tmp" -prune -o -path "./scripts" -prune -o, pero es más detallado).
  • -path "./script" -prune- si -pathdevuelve verdadero y es un directorio, devuelve verdadero para ese directorio y no descienda a él.
  • -path "./script" ! -prune- se evalúa como (-path "./script") AND (! -prune). Revierte el "siempre verdadero" de podar a siempre falso. Evita imprimir "./script"como un partido.
  • -path "./script" -prune -false- dado que -prunesiempre devuelve verdadero, puede seguirlo con -falsepara hacer lo mismo que !.
  • -o- Operador OR. Si no se especifica ningún operador entre dos expresiones, el valor predeterminado es el operador AND.

Por lo tanto, \( -path "./tmp" -o -path "./scripts" \) -prune -o -name "*_peaks.bed" -printse expande a:

[ (-path "./tmp" OR -path "./script") AND -prune ] OR ( -name "*_peaks.bed" AND print )

La impresión es importante aquí porque sin ella se expande a:

{ [ (-path "./tmp" OR -path "./script" )  AND -prune ]  OR (-name "*_peaks.bed" ) } AND print

-printse agrega mediante buscar; es por eso que la mayoría de las veces, no es necesario agregarlo en su expresión. Y dado que -prunedevuelve verdadero, imprimirá "./script" y "./tmp".

No es necesario en los demás porque cambiamos -prunepara devolver siempre falso.

Sugerencia: puede usar find -D opt expr 2>&1 1>/dev/nullpara ver cómo se optimiza y expande,
find -D search expr 2>&1 1>/dev/nullpara ver qué ruta está marcada.


0

Prueba algo como

find . \( -type f -name \*_peaks.bed -print \) -or \( -type d -and \( -name tmp -or -name scripts \) -and -prune \)

y no se sorprenda demasiado si me equivoco un poco. Si el objetivo es un ejecutivo (en lugar de imprimir), simplemente sustitúyalo en su lugar.


0

para mí, esta solución no funcionó en un comando ejecutivo con find, realmente no sé por qué, así que mi solución es

find . -type f -path "./a/*" -prune -o -path "./b/*" -prune -o -exec gzip -f -v {} \;

Explicación: igual que sampson-chen uno con las adiciones de

-prune - ignora la ruta de procedimiento de ...

-o - Entonces, si no coincide, imprima los resultados (pode los directorios e imprima los resultados restantes)

18:12 $ mkdir a b c d e
18:13 $ touch a/1 b/2 c/3 d/4 e/5 e/a e/b
18:13 $ find . -type f -path "./a/*" -prune -o -path "./b/*" -prune -o -exec gzip -f -v {} \;

gzip: . is a directory -- ignored
gzip: ./a is a directory -- ignored
gzip: ./b is a directory -- ignored
gzip: ./c is a directory -- ignored
./c/3:    0.0% -- replaced with ./c/3.gz
gzip: ./d is a directory -- ignored
./d/4:    0.0% -- replaced with ./d/4.gz
gzip: ./e is a directory -- ignored
./e/5:    0.0% -- replaced with ./e/5.gz
./e/a:    0.0% -- replaced with ./e/a.gz
./e/b:    0.0% -- replaced with ./e/b.gz

La respuesta aceptada no funcionó, pero funciona. El uso de ciruela pasa, find . -path ./scripts -prune -name '*_peaks.bed' -type f. No estoy seguro de cómo excluir varios directorios. Esto también enumera el directorio excluido de nivel superior aunque typeesté especificado. La exclusión a través de Grep parece más sencilla a menos que desee utilizar Prune para acelerar la operación de búsqueda.
— Mohnish

También tuve problemas para excluir varios directorios, pero los comentarios anteriores me dieron una respuesta que funcionó. Utilizo varias instancias de '-not -path' y en cada expresión de ruta incluyo el prefijo completo como se usa en el primer parámetro para 'buscar' y terminar cada una con un asterisco (y escapar de los puntos).
— jetset

0

Puedes probar a continuación:

find ./ ! \( -path ./tmp -prune \) ! \( -path ./scripts -prune \) -type f -name '*_peaks.bed'

2
En una pregunta anterior como esa (¡4 años!), Desea explicar por qué esta nueva respuesta es mejor o diferente, no solo el código de "volcado".
— Nic3500
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.