Comando más eficiente para buscar en la primera línea de muchos archivos (ventanas)

Comando más eficiente para buscar en la primera línea de muchos archivos (ventanas)

Soy nuevo en el ecosistema de Windows. Me han encomendado la tarea de escribir un programa que buscará en varias decenas (tal vez incluso cientos) de miles de archivos una cadena en particular. La cadena que debe coincidir es un número de serie que consta únicamente de números y letras y tiene menos de 20 caracteres. En este momento, mi programa está ejecutando el siguiente comando:

findstr /i /m /s "searchStr" "C:\Directory\To\Search\*.*"

El comando anterior funciona, sin embargo, es demasiado lento. Los archivos que puedan contener un número de serie particular solo tendrán el número de serie en la primera línea.

¿Alguien conoce una forma eficiente de buscar recursivamente en un directorio todos los archivos que contienen una cadena particular solo en la primera línea?

Respuesta1

En PowerShell (v3.0+), tal vez...

Get-ChildItem -Path x:\pathto\*.log `
| ForEach-Object {
    if (Get-Content -LiteralPath $_ -First 1 `
        | Select-String -SimpleMatch -Pattern 'serialnumber') 
    {
        Write-Output $_
    }
}

Diferentes parámetros para Get-ChildItempoder recurrir a subcarpetas, etc.; poder Get-Contentobtener más o menos contenido del archivo; y Select-Stringpuede realizar coincidencias más complejas (expresiones regulares, distinción entre mayúsculas y minúsculas, etc.).

Respuesta2

Puedo sugerir algunas opciones si no necesita usar findstr, pero antes que nada debería ver si puede restringir la búsqueda a archivos de un determinado tipo, ya que eso seguramente acelerará las cosas.

  1. Localizador de archivos LiteEn mi experiencia, es más rápido para encontrar archivos y verificar su contenido. Asegúrese de completar los campos "nombre de archivo" (si corresponde) y "texto contenido", así como el directorio de inicio.

  2. ag -il "searchStr":agestá diseñado para la velocidad, por lo que debería brindarle resultados rápidamente. Asegúrese de restringir la búsqueda por tipo de archivo si puede, aunque los archivos binarios ya se omiten de forma predeterminada. También disponible bajoCygwin.

  3. find -exec awk 'BEGIN {IGNORECASE=1} NR==1 && /searchStr/ {print FILENAME": "$0}' {} \;Pruebe esto si tiene Cygwin u otro entorno similar a POSIX disponible, para comprobar su idea de buscar solo la primera línea. Combine findpara obtener los nombres de los archivos (y con suerte también filtrarlos) y awkverifique la primera línea e imprímala junto con el nombre del archivo.
  4. find | parallel 'perl -lane '\'' print "$ARGV: $_" if $. == 1 and /searchStr/i '\'' {}'Otra idea para intentar acelerar las cosas es poner a trabajar los núcleos e hilos disponibles: eso es lo queparalelo GNUes para. Este ejemplo tiene deportes perl, pero hace lo mismo que awkel 3.anterior. Aquí hay un desglose del comando:

    findbusque archivos en el directorio actual y sus subdirectorios. Puede especificar un directorio diferente para buscar y un patrón de archivo o extensión para filtrar: find /cygdrive/c/Directory/To/Search -iname "*.txt".

    |"tubería", es decir, alimenta la lista de resultados al siguiente comando.

    parallelejecute el siguiente comando en paralelo.

    perlLenguaje de scripting que sobresale en la manipulación de archivos de texto, puede reemplazar sedo awk.

    -laneútil conjunto de interruptores para perl one-liners.

    '\''Apóstrofe escapado, necesario ya que ya abrimos un apóstrofe establecido después parallel.

    print "$ARGV: $_"imprime el nombre del archivo ( $ARGV), dos puntos, un espacio y la línea completa ( $_).

    ifSólo ejecute la instrucción anterior si se cumplen las siguientes condiciones.

    $. == 1El número de línea ( $.) es igual a uno ( 1), es decir, estamos viendo la primera línea del archivo.

    andTambién se debe cumplir la siguiente condición.

    /searchStr/ila línea que se examina contiene el texto searchStr, sin distinguir entre mayúsculas y minúsculas.

    '\''otro apóstrofe escapado marca el final de la perlinstrucción.

    {}esto será sustituido por parallelcada uno de los nombres de archivo pasados ​​por find.

    'final de la parallelinstrucción.

Actualizar:Ambos awky perlleen el archivo completo incluso si las acciones están vinculadas solo a la primera línea. La solución es detener explícitamente la elaboración en la línea 2:

find -exec awk 'BEGIN {IGNORECASE=1} NR > 1 {exit} /searchStr/ {print FILENAME": "$0}' {} \; find | parallel 'perl -lape '\'' exit if $. == 2; print "$ARGV: $_" if /searchStr/i '\'' {}'

información relacionada