Busque múltiples patrones de un archivo usando el comando buscar

Busque múltiples patrones de un archivo usando el comando buscar

Existe una opción que grep -f MY_FILEle permite buscar patrones tomados de un archivo, en lugar de especificarlos directamente en la línea de comando.

¿Existe una opción para hacer algo similar con el findcomando y dejar que lea los patrones para buscar desde un archivo de entrada?

Respuesta1

findno parece tener tales capacidades integradas, pero puede usarlas xargspara construir múltiples findcomandos usando argumentos de un archivo, como:

xargs -a patterns.txt -I% find Pictures/ -name %

donde patterns.txtestaría una lista de patrones adecuados para el -namefiltro, un patrón por línea. Preste atención a que no tenga espacios iniciales o finales allí, ya que estarían incluidos en el patrón. Un ejemplo:

*.jpg
2018-06-*
*foo*
unicorn.png

Nota:Si bien esta respuesta parece bastante fácil y elegante, en los comentarios se señaló correctamente que tiene algunas desventajas:

El rendimiento no es demasiado bueno para carpetas grandes o muchos patrones, ya que se ejecutará finduna vez por patrón en su archivo, lo que hará que explore repetidamente toda la carpeta de búsqueda.

Por eso, también si tiene varios patrones que potencialmente podrían superponerse (como *.jpgy *foo*), los archivos que coincidan con más de un patrón aparecerán tantas veces en el resultado. Si de todos modos solo está imprimiendo los nombres, puede canalizar la salida sort -upara eliminar duplicados, pero si, por ejemplo, elimina esos resultados o ejecuta algún -execcomando en ellos, esto puede ser menos deseable.

Si alguna de estas desventajas es un problema para su caso de uso, tal vez sea mejor optar por una de las respuestas alternativas.

Explicación del comando:

  • xargsleerá una lista de argumentos y los usará para construir y ejecutar una nueva línea de comando.
  • -a patterns.txtle dice que lea ese archivo en lugar de la entrada estándar.
  • -I%le dice que no simplemente agregue los argumentos que leyó al final de la línea de comando, sino que reemplace el %carácter en la línea de comando que proporcionó con un argumento. Esto implica crear y ejecutar un comando separado por argumento de entrada.
  • find Pictures/ -name %es la línea de comando en la que queremos insertar los argumentos, reemplazando el %. No es necesario citarlo aquí, porque xargsse asegurará de que cada argumento que inserte se trate como un token único y no se divida por sí solo. Por supuesto, puede reemplazar Pictures/con su propio directorio de búsqueda y también usar filtros diferentes o más además de -name. Debido a que usamos la opción de inserción, también puede agregar acciones como -exec ...al final del comando.

Respuesta2

Simplemente puede crear una expresión regular a partir del contenido de su archivo usando paste -sd'|' bar.

find ~/foo -regextype egrep -regex "^.*/($(paste -sd'|' bar))$"

La expresión regular será"^.*/(a|b)$"

Respuesta3

No muy recientemente, hice unrespuestaque combina múltiples patrones usando -regexflag en find. En base a eso, podemos crear un pequeño script o función para hacer el mismo trabajo, pero construyendo la lista de patrones a partir del archivo.

#!/bin/bash

read_file(){
    local full_pattern=""
    while IFS= read -r pattern; do
        if [ -z "$full_pattern"  ];then
            full_pattern="$pattern"
            continue
        fi
        full_pattern="$full_pattern\|$pattern"
    done < "$1"
    echo "$full_pattern"
}

fp=$(read_file "$1" )
find "$2" -type f -regex ".*\($fp\).*$" 

Qué hace esto:

  • llamamos script as findf.sh input.txt /etc, donde el primer parámetro posicional es el archivo con patrones y el segundo, el directorio donde buscar. GNU find asume .el directorio si se omite el argumento del directorio, por lo que $2no es necesario.
  • La función read_filelee el archivo de entrada que es el primer parámetro posicional del script. Esto crea un patrón para -regexla bandera.
  • Este patrón se repite en el bloque "principal" del script, se guarda en fpuna variable y se pasa al findcomando.

información relacionada