patrón `find -name` que coincide con múltiples patrones


335

Estaba tratando de obtener una lista de todos los archivos python y html en un directorio con el comando find Documents -name "*.{py,html}".

Luego apareció la página del manual:

Las llaves dentro del patrón ('{}') no se consideran especiales (es decir, find. -Name 'foo {1,2}' coincide con un archivo llamado foo {1,2}, no con los archivos foo1 y foo2.

Como esto es parte de una cadena de tuberías, me gustaría poder especificar qué extensiones coincide en tiempo de ejecución (sin codificación rígida). Si find simplemente no puede hacerlo, un perl one-liner (o similar) estaría bien.

Editar: La respuesta que finalmente se me ocurrió incluye todo tipo de basura, y también es un poco larga, así que la publiqué como respuesta a la picazón original que estaba tratando de rascar. Siéntete libre de hackear eso si tienes mejores soluciones.



Una utilidad que a menudo se pasa por alto e infrautilizada también es locate, aunque con la advertencia de que la actualización internab puede no estar actualizada. Pero es rapido.
michael

Estoy votando para cerrar esta pregunta como fuera de tema porque pertenece a Unix y Linux
Dan Dascalescu

Respuestas:


481

Uso -o, que significa "o":

find Documents \( -name "*.py" -o -name "*.html" \)

Tendría que construir esa línea de comando mediante programación, lo cual no es tan fácil.

¿Estás usando bash (o Cygwin en Windows)? Si es así, debería poder hacer esto:

ls **/*.py **/*.html

que podría ser más fácil de construir mediante programación.


3
Estoy usando zsh, que, como regla general, admite todos los bashismos, y más.
Xiong Chiamiov el

12
Zsh admite la **búsqueda recursiva; Bash solo lo admite en las versiones 4.0 y posteriores, y solo con shopt -s globstar.
ephemient

2
¿Cuántos args puedes tener? Tengo una lista potencialmente grande de archivos .gcda (datos de cobertura) para construir
Jasper Blues

40
Necesitas rodear los dos -names con paréntesis, si lo estás usando -exec. Por ejemplofind Documents \( -name "*.py" -o -name "*.html" \) -exec file {} \;
artbristol

2
El comentario de @artbristol es muy relevante si, por ejemplo, está agregando un -print0para manejar nombres de archivos con espacios.
nimrodm

63

Algunas ediciones de find, principalmente en sistemas Linux, posiblemente en otras, también admiten las opciones -regex y -regextype, que encuentran archivos con nombres que coinciden con la expresión regular.

por ejemplo

find . -regextype posix-egrep -regex ".*\.(py|html)$" 

debería hacer el truco en el ejemplo anterior. Sin embargo, esta no es una función de búsqueda POSIX estándar y depende de la implementación.


1
interesante pero más complejo que las otras respuestas
m1k3y3

12
Más simple: find . -regex ".*\.\(py\|html\)$"esto funciona porque encuentra valores predeterminados para las expresiones regulares de estilo Emacs, que son ligeramente diferentes, por lo que no tiene que especificar el tipo de expresión regular.
robru

2
Si tiene muchas expresiones -regextype posix-egrepes útil (de lo contrario, necesitaría escapar de muchos caracteres). Este es el comando find que he usado para un dist-hook que construye un zip de distribución de Windows (encuentra los archivos para cambiar y en el archivo los cambia a dos-eol): find -regextype posix-egrep -regex ".*(\.([chyl]|def|cpy|cob|conf|cfg)|(README|ChangeLog|AUTHORS|ABOUT-NLS|NEWS|THANKS|TODO|COPYING.*))$" -exec sed -i -e 's/\r*$/\r/' {} \;
Simon Sobisch

32

Podrías agregar más -namecláusulas mediante programación , separadas por -or:

find Documents \( -name "*.py" -or -name "*.html" \)

O bien, elija un bucle simple:

for F in Documents/*.{py,html}; do ...something with each '$F'... ; done

@ user2284570: entonces no hay *.pyarchivos o tienes alguna versión extraña de find. El comando mencionado anteriormente funciona bien.
Stephan202

No, lo estoy usando -iname. Solo devuelve *.pyarchivos si lo escribe en la última posición (también lo iname *.htmles la primera expresión) . Yo uso el comando en Debian.
usuario2284570

¿Estás usando comillas? Eso es muy importante
Stephan202

1
¿Es un -o un -o?
Stephane

1
@StephaneEybert: bien está bien, pero solo el último cumple con POSIX (según la página de manual).
Stephan202

16

Esto encontrará todos los archivos .c o .cpp en Linux

$ find . -name "*.c" -o -name "*.cpp"

No necesita el paréntesis escapado a menos que esté haciendo algunas modificaciones adicionales. Aquí, desde la página de manual, dicen si el patrón coincide, imprímalo. Quizás están tratando de controlar la impresión. En este caso, -print actúa como un condicional y se convierte en un condicional "AND'd". Evitará que se impriman los archivos .c.

$ find .  -name "*.c" -o -name "*.cpp"  -print

Pero si le gusta la respuesta original, puede controlar la impresión. Esto también encontrará todos los archivos .c.

$ find . \( -name "*.c" -o -name "*.cpp" \) -print

Un último ejemplo para todos los archivos fuente c / c ++

$ find . \( -name "*.c" -o -name "*.cpp"  -o -name "*.h" -o -name "*.hpp" \) -print

11

Tenía una necesidad similar Esto funcionó para mí:

find ../../ \( -iname 'tmp' -o -iname 'vendor' \) -prune -o \( -iname '*.*rb' -o -iname '*.rjs' \) -print

3
Perfecto. Pero me parece un poco extraño que no funcione sin el()
pedrofurla

Quería encontrar archivos que coincidieran con * .c * .cpp o * .cc Con solo patrones de dos nombres, no necesitaba parens, pero con patrones de tres nombres unidos con dos -o patrones find -name "*.cpp" -o -name "*.c" -o -name "*.cc" -print0tuve que usar un par de parens para agrupe el segundo u operador. find -name "*.cpp" -o \( -name "*.c" -o -name "*.cc" \) -print0Puede ser que -print0, que siempre es "verdadero", haya afectado la lógica.
Cardiff space man

5

Mi defecto ha sido:

find -type f | egrep -i "*.java|*.css|*.cs|*.sql"

Al igual que el proceso menos ejecutivo de findejecución por Brendan Long y Stephan202 et al .:

find Documents \( -name "*.py" -or -name "*.html" \)


3
ese no es un uso correcto de egrepregexp, más bien, tienes un globo de shell donde se debe usar una expresión regular. (Además, el finduso típico es:, find {directory} [options...] [action]donde, según impl, directorypuede ser predeterminado .y actionpredeterminado -print, pero seré explícito). Entonces, en su lugar, use algo como: find . -type f -print | egrep -i '\.java$|\.css$|\.cs$|\.sql$' Pero también, como alternativa realmente rápida a find, uno también podría intente locatede manera similar (aunque no necesariamente actualizado, ya que consulta una base de datos interna para obtener una lista de archivos)
michael

2
#! /bin/bash
filetypes="*.py *.xml"
for type in $filetypes
do
find Documents -name "$type"
done

simple pero funciona :)


1

Necesitaba eliminar todos los archivos en directorios secundarios, excepto algunos archivos. Lo siguiente funcionó para mí (tres patrones especificados):

find . -depth -type f -not -name *.itp -and -not -name *ane.gro -and -not -name *.top -exec rm '{}' +

1

\(\)Se requieren llaves dentro del patrón para el patrón de nombre conor

find Documents -type f \( -name "*.py" -or -name "*.html" \)

Mientras que para el patrón de nombre con andoperador no es necesario

find Documents -type f ! -name "*.py" -and ! -name "*.html" 

0

Esto funciona en AIX Korn Shell.

find *.cbl *.dms -prune -type f -mtime -1

Esto está buscando *.cblo *.dmsque tienen 1 día de antigüedad, solo en el directorio actual, omitiendo los subdirectorios.


0
find MyDir -iname "*.[j][p][g]"
+
find MyDir -iname "*.[b][m][p]"
=
find MyDir -iname "*.[jb][pm][gp]"

2
Tenga en cuenta que este último coincidirá con foo.jmg pero ninguno de los dos primeros lo hará.
copper.hat

0

Qué pasa

ls {*.py,*.html}

Enumera todos los archivos que terminan con .py o .html en sus nombres de archivo

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.