Der effizienteste Befehl zum Durchsuchen der ersten Zeile vieler Dateien (Windows)

766
tpdietz

Ich bin neu im Windows-Ökosystem. Ich wurde mit dem Schreiben eines Programms beauftragt, das mehrere 10er (vielleicht sogar 100er) Tausende von Dateien nach einer bestimmten Zeichenfolge durchsucht. Die Zeichenfolge, die abgeglichen werden muss, ist eine Seriennummer, die nur aus Zahlen und Buchstaben besteht und weniger als 20 Zeichen umfasst. Im Moment führt mein Programm den folgenden Befehl aus:

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

Der obige Befehl funktioniert, ist jedoch zu langsam. Die Datei (en), die eine bestimmte Seriennummer enthalten könnten, enthalten nur die Seriennummer in der ersten Zeile.

Kennt jemand eine effiziente Methode zum rekursiven Durchsuchen eines Verzeichnisses nach allen Dateien, die nur in der ersten Zeile eine bestimmte Zeichenfolge enthalten?

1
Wenn Sie eine Windows-Implementierung des Unix-Dienstprogramms `sed` verwenden, sollte der folgende Befehl effizient funktionieren:` sed -sn '1s / searchStr / & / p' SearchPath \ *. * `. Leider zeigt es Ihnen die serielle Zeichenfolge, nicht aber die Dateinamen. Um die Dateinamen anzuzeigen, verwenden Sie eine `for`-Schleife, die die Ausgabe der aktuellen Datei prüft und gegebenenfalls deren Namen anzeigt. Bevor Sie das alles tun, überprüfen Sie, ob der direkte Anruf schnell genug ist. AFH vor 8 Jahren 1
Ihr Programm ruft also nur findstr auf? Beim Lesen Ihrer Beschreibung schien es, als ob Sie Ihren eigenen Textsuchcode schreiben sollten. Karan vor 8 Jahren 0
Ich versuchte herauszufinden, mit welchen Tools ich bei der Suche helfen konnte. Ich könnte jede Datei selbst analysieren, aber ich dachte, ein eingebautes "bewährtes" Programm könnte effizienter sein als das, was ich mir vorgestellt habe. Aber vielleicht nicht ... tpdietz vor 8 Jahren 0

2 Antworten auf die Frage

2
jimbobmcgee

In PowerShell (v3.0 +) vielleicht ...

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

Verschiedene Parameter zum Get-ChildItemWiederherstellen von Unterordnern usw .; zu Get-Contentmehr oder weniger Inhalt aus der Datei zu erhalten; und Select-Stringkann komplexere Übereinstimmungen durchführen (regulärer Ausdruck, Groß- und Kleinschreibung usw.).

Schöne Antwort, die einige Fähigkeiten von Powershell zeigt; Ich dachte, ich würde Links zur aktuellen Dokumentation für [`Get-ChildItem`] hinzufügen (https://msdn.microsoft.com/en-us/powershell/reference/5.1/microsoft.powershell.management/get-childitem). , [`Get-Content`] (https://msdn.microsoft.com/de-de/powershell/reference/5.1/microsoft.powershell.management/get-content) und [` Select-String`] (https: //msdn.microsoft.com/en-us/powershell/reference/5.1/microsoft.powershell.utility/select-string). simlev vor 6 Jahren 0
1
simlev

Ich kann ein paar Optionen vorschlagen, wenn Sie sie nicht verwenden müssen findstr, aber Sie sollten zunächst prüfen, ob Sie die Suche auf Dateien eines bestimmten Dateityps beschränken können, da dies die Sache sicherlich beschleunigen wird.

  1. FileLocator Lite ist meiner Erfahrung nach schneller beim Auffinden von Dateien und Überprüfen des Inhalts. Stellen Sie sicher, dass Sie die Felder "Dateiname" (falls zutreffend) und "enthaltenen Text" sowie das Startverzeichnis angeben.

  2. ag -il "searchStr": ag ist auf Geschwindigkeit ausgelegt, so dass Sie schnell Ergebnisse erzielen können. Beschränken Sie die Suche nach Dateityp, wenn Sie können, obwohl binäre Dateien standardmäßig bereits übersprungen werden. Auch unter Cygwin erhältlich .

  3. find -exec awk 'BEGIN NR==1 && /searchStr/ ' {} \;Probieren Sie dies aus, wenn Sie Cygwin oder eine andere POSIX-ähnliche Umgebung zur Verfügung haben, um zu prüfen, ob Sie nur in der ersten Zeile suchen. Kombinieren Sie find, um die Dateinamen zu erhalten (und hoffentlich auch zu filtern) und awkdie erste Zeile zu überprüfen und zusammen mit dem Dateinamen zu drucken.
  4. find | parallel 'perl -lane '\'' print "$ARGV: $_" if $. == 1 and /searchStr/i '\'' {}'Eine weitere Idee, die Dinge zu beschleunigen, besteht darin, verfügbare Kerne und Threads zum Laufen zu bringen. Dafür gibt es GNU parallel . Dieses Beispiel Sport perl, aber es macht das gleiche wie awkin 3.oben. Hier ist eine Befehlsaufteilung:

    findSuchen Sie nach Dateien im aktuellen Verzeichnis und dessen Unterverzeichnissen. Sie können ein anderes Verzeichnis angeben, in suchen und ein Dateimuster oder Erweiterung filtern auf: find /cygdrive/c/Directory/To/Search -iname "*.txt".

    | "Pipe", dh die Ergebnisliste wird an den nächsten Befehl übergeben.

    parallel Führen Sie den nächsten Befehl parallel aus.

    perlSkriptsprache, die sich bei der Bearbeitung von Textdateien auszeichnet, ersetzen sedoder ersetzen kann awk.

    -lane nützliche Schalter für Perl-Einzeiler.

    '\''Apostroph entkommen, benötigt, da wir bereits einen Apostroph nach dem Öffnen geöffnet haben parallel.

    print "$ARGV: $_"drucke den Dateinamen ( $ARGV), einen Doppelpunkt, ein Leerzeichen und die vollständige Zeile ( $_).

    if Führen Sie den vorherigen Befehl nur aus, wenn die folgenden Bedingungen erfüllt sind.

    $. == 1Zeilennummer ( $.) ist gleich Eins ( 1), dh wir betrachten die erste Zeile der Datei.

    and Die folgende Bedingung muss ebenfalls erfüllt sein.

    /searchStr/iDie zu untersuchende Zeile enthält den Text ohne Berücksichtigung der searchStrGroß- und Kleinschreibung.

    '\''Ein anderer Apostroph markiert das Ende der perlAnweisung.

    {}Dies wird durch paralleljeden der weitergeleiteten Dateinamen ersetzt find.

    'Ende der parallelAnweisung.

Update: Beides awkund perlLesen der gesamten Datei, auch wenn Aktionen nur an die erste Zeile gebunden sind. Die Lösung besteht darin, die Ausarbeitung in Zeile 2 explizit einzustellen:

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