Pregunta

Es necesario crear un script para buscar a través de justo por debajo de un millón de archivos de texto, código, etc., para encontrar coincidencias y luego salida de todos los accesos a un patrón de cadena en particular a un archivo CSV.

Hasta ahora he hecho esto;

$location = 'C:\Work*'

$arr = "foo", "bar" #Where "foo" and "bar" are string patterns I want to search for (separately)

for($i=0;$i -lt $arr.length; $i++) {
Get-ChildItem $location -recurse | select-string -pattern $($arr[$i]) | select-object Path | Export-Csv "C:\Work\Results\$($arr[$i]).txt"
}

Esto devuelve a mí un archivo CSV denominado "foo.txt" con una lista de todos los archivos con la palabra "foo" en él, y un archivo llamado "bar.txt" con una lista de todos los archivos que contienen la palabra " bar".

¿Hay alguna manera de que nadie puede pensar en optimizar esta secuencia de comandos para hacer que funcione más rápido? O ideas sobre cómo hacer un guión completamente diferente, pero equivalente que simplemente funcione más rápido?

Toda la entrada apreciada!

¿Fue útil?

Solución

Si los archivos no son enormes y se pueden leer en la memoria a continuación, esta versión debería funcionar bastante rápido (y mi rápida y sucia de prueba local parece probar que):

$location = 'C:\ROM'
$arr = "Roman", "Kuzmin"

# remove output files
foreach($test in $arr) {
    Remove-Item ".\$test.txt" -ErrorAction 0 -Confirm
}

Get-ChildItem $location -Recurse | .{process{ if (!$_.PSIsContainer) {
    # read all text once
    $content = [System.IO.File]::ReadAllText($_.FullName)
    # test patterns and output paths once
    foreach($test in $arr) {
        if ($content -match $test) {
            $_.FullName >> ".\$test.txt"
        }
    }
}}}

Notas: 1) caminos y patrones en el ejemplo de la mente cambiado; 2) los archivos de salida no son sino CSV texto plano; no hay mucha razón en CSV si usted está interesado sólo en caminos -. archivos de texto plano un camino por línea hará

Otros consejos

a suponer que 1) los archivos no son demasiado grandes y se puede cargar en la memoria, 2) lo que realmente desea que la ruta del archivo, vamos que los partidos (no la línea, etc.).

Traté de leer el archivo sólo una vez y luego iterar a través de las expresiones regulares. Hay una cierta ganancia (que es un más rápido que la solución original), pero el resultado final dependerá de otros factores como el tamaño de los archivos, el recuento de archivos, etc.

También la eliminación de 'ignorecase' hace que sea más rápido un poco.

$res = @{}
$arr | % { $res[$_] = @() }

Get-ChildItem $location -recurse | 
  ? { !$_.PsIsContainer } |
  % { $file = $_
      $text = [Io.File]::ReadAllText($file.FullName)
      $arr | 
        % { $regex = $_
            if ([Regex]::IsMatch($text, $regex, 'ignorecase')) {
              $res[$regex] = $file.FullName
            }
        }
  }
$res.GetEnumerator() | % { 
  $_.Value | Export-Csv "d:\temp\so-res$($_.Key).txt"
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top