Rekursive Batchdatei

925
MCZ

Ich habe eine Datei, die so aussieht:

head1,head2,head3,head4,head5,head6 a11,a12,keyA,a14,a15,a16 a21,a22,keyB,a24,a25 a31,a32,keyC,a34 a41,a42,keyB,a44,a44 a51,a52,keyA,a54,a55,a56 a61,a62,keyA,a64,a65,a66 a71,a72,keyC,a74 some message 

Ziel: Schreiben einer Liste eindeutiger Schlüssel in eine Textdatei. Das Ergebnis für die oben beschriebene Datei sollte beispielsweise lauten:

keyA, keyB, keyC

Hier ist der Pseudocode, den ich in Batchdatei implementieren möchte recur.bat

  1. Lesen Sie die zweite Zeile der Eingabedatei
  2. Wenn in der zweiten Zeile kein Schlüssel vorhanden ist, fahren Sie mit return fort
  3. keyXAn Liste anhängen
  4. FINDSTR /v keyX inputfile
  5. Rohrergebnisse bis recur.bat

Ich weiß nicht, ob dies der effizienteste Weg ist, ohne die eigentliche Programmiersprache zu verwenden.

Irgendwelche Vorschläge für den eigentlichen Batchdatei-Code?

0
Willkommen bei Super User, MCZ! Also, was ist deine Frage wirklich? Sind Sie irgendwo beim Implementieren der Datei steckengeblieben? Was hast du schon gemacht? Bitte überprüfen Sie auch die Vorschau Ihrer Beiträge, bevor Sie sie absenden. Sie müssen den Code um 4 Leerzeichen einrücken oder die Tastenkombination "Strg-K" drücken. slhck vor 12 Jahren 1

3 Antworten auf die Frage

1
Bob

Sie können PowerShell verwenden, das mit Windows Vista oder höher geliefert wird:

$keys = @( ); Import-Csv input.txt | ForEach-Object {  if (!$_.head3) { $keys | Out-File output.txt; break; } else { if (!($keys -contains $_.head3)) { $keys += $_.head3; } } } 

Dies kann bei großen Datenmengen langsam sein, da es ein Array ( $keys) zum Halten und Überprüfen eindeutiger Schlüssel verwendet. Eine alternative Methode besteht darin, alles in eine Textdatei zu schreiben, zu sortieren und durchzuarbeiten Get-Unique. Eine andere Alternative ist die Verwendung einer Hashtabelle (würde nicht bei der Speichernutzung helfen, wäre aber schneller als die Überprüfung, ob etwas in einem Array vorhanden ist).

Dies verwendet Import-Csv, wobei die erste Zeile als Überschrift verwendet wird. Es übergibt dann ein Array von Objekten (Linien) an ForEach-Object. $_ist eine Variable, die auf jedes Objekt (Zeile) verweist. .head3ist die Eigenschaft mit dem Namen head3, die in den Beispieldaten als Spalte mit den Schlüsseln definiert ist. Er prüft, ob in dieser Zeile ein Wert für diese Spalte vorhanden ist. Wenn nicht, wird es in eine Datei ausgegeben und gemäß Ihrem Pseudocode beendet. Beachten Sie, dass Werte, die keine Schlüssel sind, möglicherweise akzeptiert werden. Wenn Sie strengere Regeln für einen Schlüssel haben / benötigen, können Sie die Länge überprüfen oder einen RegEx-Musterabgleich durchführen.

a71,a72,a73,a74 a71,a72,keyC,a74 some message a71,a72,keyD,a74 

a73Zählt derzeit als Schlüssel (in der dritten Spalte head3). Das Programm endet um some message, da es keine dritte Spalte hat und nicht lesen kann keyD.

Wenn die Zeile über eine Schlüsselspalte verfügt, wird geprüft, ob der Schlüssel bereits im Array vorhanden ist, und wenn nicht, wird er hinzugefügt. Beachten Sie, dass -containsdie Groß- und Kleinschreibung nicht beachtet wird. Wenn dies ein Problem ist, kann es geändert werden.

Sie müssen also wahrscheinlich input.txt output.txtund head3mit den richtigen Namen ersetzen . Dies war die einfachste Lösung, die die Reihenfolge der Daten nicht ändert, obwohl schnellere möglich sind, falls dies erforderlich ist.

1
Bob

Separate Antwort, da dies im Wesentlichen eine andere Lösung ist

Hier ist eine cmd / batch-Version.

@echo off type NUL>output.txt for /f "tokens=1,3 delims=, skip=1" %%a in (input.txt) do ( if "%%b"=="" goto :eof findstr "^%%b$" output.txt > NUL if ERRORLEVEL 1 echo %%b>>output.txt ) 

Es erstellt output.txt und liest dann input.txt mit forund ,als Trennzeichen. Die erste Zeile wird übersprungen.

Das erste token ( tokens=1,3) musste gelesen werden, um es in der some messageZeile zu stoppen, da es die Zeile einfach überspringen und fortsetzen würde, wenn das angeforderte token ( tokens=3) nicht vorhanden wäre - und niemals die if. %%aist das erste angeforderte token ( 1), %%bist das zweite ( 3).

a71,a72,a73,a74 a71,a72,keyC,a74 some message a71,a72,keyD,a74 

keyDwird nicht gelesen, da es an der vorherigen Zeile stoppt (hat kein drittes Token). Allerdings a73wird gezählt.

Dies wird findstrin der Ausgabedatei verwendet, um zu überprüfen, ob der Schlüssel bereits vorhanden ist - überhaupt nicht effizient, aber es funktioniert. Das RegEx wird verwendet, um sicherzustellen, dass es mit der gesamten Zeile übereinstimmt. Wenn ein Schlüssel vollständig im anderen Schlüssel enthalten ist, stimmt er nicht überein (dh er keyAstimmt nicht überein key). Die Ausgabe wird geleitet, NULum die Dinge ruhig zu halten.

Wenn der Schlüssel nicht in der Ausgabedatei enthalten ist, wird er angehängt.

0
Michael S.

In Bash (Cygwin kann unter Windows verwendet werden), ist dies einfach:

1.) durch Newline ersetzen (\ n)

sed -i 's/,/\n/g' superuser.txt 

Bevor Sie hatten:

head1,head2,head3,head4,head5,head6 a11,a12,keyA,a14,a15,a16 a21,a22,keyB,a24,a25 a31,a32,keyC,a34 a41,a42,keyB,a44,a44 a51,a52,keyA,a54,a55,a56 a61,a62,keyA,a64,a65,a66 a71,a72,keyC,a74 

Jetzt hast du:

head1 head2 head3 head4 head5 head6 a11 a12 keyA a14 a15 a16 a21 a22 keyB a24 a25 a31 a32 keyC a34 a41 a42 keyB a44 a44 a51 a52 keyA a54 a55 a56 a61 a62 keyA a64 a65 a66 a71 a72 keyC a74 

2.) Suchen Sie nach "Schlüssel", sortieren Sie die Ergebnisse und entfernen Sie Duplikate

grep -F key superuser.txt | sort | uniq 

Gibt Ihnen:

keyA keyB keyC 
Ich bin mir ziemlich sicher, dass die Datei des OP nicht in einer Zeile war, sie hat nur die Formatierung falsch gemacht. Siehe die aktualisierte Frage. slhck vor 12 Jahren 0
Sie müssen native Windows-Befehle verwenden. MCZ vor 12 Jahren 0
keyX = ein Hexadezimalwert (String) im Bereich von 0000 bis FFFF. Daher ist das Wort "Schlüssel" in keiner Zeile der Spalte 3 enthalten. MCZ vor 12 Jahren 0
@MCZ Enthält dies PowerShell? da dies zwar mit "for" in cmd möglich ist, wäre PowerShell definitiv "sauberer". Bob vor 12 Jahren 0
@ Bob ... Leider muss ich Befehle verwenden, die mit Windows geliefert werden. Alle Tools von Drittanbietern erfordern Administratorrechte, die ich nicht habe. MCZ vor 12 Jahren 0
Übrigens, die Dateien, mit denen ich arbeite, sind ca. 1/2 GB groß. MCZ vor 12 Jahren 0
@MCZ PowerShell wird mit Vista und neuer geliefert. Bob vor 12 Jahren 0
@ Bob ... Werde hineinschauen. Ich habe keine PowerShell verwendet. Ich bin ein Anfänger bei der Verwendung von Batch-Dateien und kenne keine Syntax für meine Lösung. Welche Befehle empfehle ich bei der Verwendung von PowerShell? Allgemeine Vorgehensweise, die Sie ergreifen würden? Die effizienteste Lösung, die ich bisher habe, dauert etwa 15 Sekunden, um die 500 MB-Datei zu lesen (mithilfe der MATLAB Textscan-Funktion) MCZ vor 12 Jahren 0