joshuatree
Goto Top

Script zum vergleich von Dateien

Hallo,
das folgende Script soll Objfile1 sequentiell auslesen und jeden Eintrag in ObjFile2 suchen.
Im Moment läuft das Script nur einmal durch das heißt die Function main() wird nur mit einem, dem ersten, Suchbegriff durchlaufen
das Script scheint nicht zurück zu kommen um sich den zweiten Suchbegriff zu holen. Warum, wie kann ich das korrigieren oder besser machen?

Gruss
Andreas

dim zeile,Suchbegriff,FileSystem,OutPutFile,OUtPutFile2
Set FileSystem = WScript.CreateObject("Scripting.FileSystemObject")  

Set objFSO = CreateObject("Scripting.FileSystemObject")  
Set objFile1 = objFSO.OpenTextFile("C:\Temp\Dis-User-in-delOU.csv",1)  
Set objFile2 = objFSO.OpenTextFile("C:\Temp\ts-Verzeichnisse-die-fehlen.csv",1)  
i = 0
u = 0




Do Until objFile1.AtEndOfStream
Suchbegriff = objFile1.ReadLine
call main()

loop
Function main()
Do Until objFile2.AtEndOfStream
Zeile = objFile2.ReadLine

		If InStr(1,Zeile,Suchbegriff,1) Then
			
			i = i + 1
			else
				
				u = u + 1
    
  end if
Loop
end function
call msgbox ("Suchbegriff " & Suchbegriff & " " & i & "x gefunden",16,"Abschlussmeldung")  
call msgbox ("Suchbegriff " & Suchbegriff & " " & u & "x nicht gefunden",16,"Abschlussmeldung")  
Kommentar vom Moderator Biber am Aug 13, 2009 um 20:53:34 Uhr
Tippfehler im Originaltitel "Scipt zum vergleich von Dateien" berichtigt.

Content-Key: 122570

Url: https://administrator.de/contentid/122570

Printed on: April 26, 2024 at 10:04 o'clock

Member: bastla
bastla Aug 12, 2009 at 10:15:35 (UTC)
Goto Top
Hallo JoshuaTree!

Wenn Du für jede Zeile in objFile1 eine Ausgabe erhalten willst, musst Du diese Ausgabe natürlich innerhalb der Schleife vornehmen (und auch die Zähler jeweils innerhalb der Schleife zurücksetzen)

Alternative zu Deinem Ansatz: Erspare Dir die (an dieser Stelle ohnehin suboptimal platzierte "Function" - die, von der Verwendung her, außerdem eigentlich ein "Sub" wäre) und packe alles in die erste Schleife - dazu müsstest Du nur die Zeilen 15 bis 18 sowie 31 entfernen und am Ende eine Zeile "Loop" ergänzen (und, wie vorher schon angesprochen, die Zeilen 7 und 8 innerhalb der Schleife verwenden).
Abgesehen davon ist die Vorgangsweise ziemlich ineffektiv. Wenn Du schon nicht eine Suche mit "regulären Ausdrücken" durchführen willst, wäre es aber sinnvoll, zunächst die beiden Dateien in Arrays (und damit in den Arbeitsspeicher) einzulesen und damit nur einmal auf die Dateien zugreifen zu müssen - das sähe etwa so aus:
Set objFSO = CreateObject("Scripting.FileSystemObject")  
Text1 = Split(objFSO.OpenTextFile("C:\Temp\Dis-User-in-delOU.csv").ReadAll, vbCrLF)  
Text2 = Split(objFSO.OpenTextFile("C:\Temp\ts-Verzeichnisse-die-fehlen.csv").ReadAll, vbCrLF)  

For Each Suchbegriff In Text1
    i = 0
    u = 0

    For Each Zeile In Text2
        If InStr(1, Zeile, Suchbegriff, 1) Then
            i = i + 1
        Else
            u = u + 1
        End If
    Next

    'Call MsgBox("Suchbegriff " & Suchbegriff & " " & i & "x gefunden", 16, "Abschlussmeldung")  
    'Call MsgBox("Suchbegriff " & Suchbegriff & " " & u & "x nicht gefunden", 16, "Abschlussmeldung")  
    WScript.Echo "Suchbegriff " & Suchbegriff & " " & i & "x gefunden"  
    WScript.Echo "Suchbegriff " & Suchbegriff & " " & u & "x nicht gefunden" & vbCrLF  
    
Next
Anmerkungen:
Wenn Du anstelle von "MsgBox" ein "WScript.Echo" verwendest, kannst Du wesentlich bequemer (nämlich an der Kommandozeile mit zB "cscript //nologo D:\DeinScript.vbs") testen, da Du dann nicht jede Ausgabe einzeln bestätigen musst. Wird das Script über "wscript" (also zB per Doppelklick) gestartet, erhältst Du für jedes "WScript.Echo" wieder eine MsgBox ...

Die Variablendeklarationen habe ich eingespart, da diese mE nur dann sinnvoll sind, wenn auch konsequent alle Variablen deklariert werden und dies per "Option Explicit" auch kontrolliert wird - in einem kurzen und übersichtlichen Script kannst Du aber auch ohne Deklarationen zurechtkommenn.

Grüße
bastla

P.S.: Vielleicht fällt Dir auch noch ein etwas aussagekräftigerer Titel für den Thread ein ...
Member: JoshuaTree
JoshuaTree Aug 12, 2009 at 13:30:41 (UTC)
Goto Top
Hallo bastla,

es kommt mir vor als würdest du den ganzen Support alleine hier machen.
Vielen vielen Dank dir wie immer sehr hilfreich.

Gruss
Andreas
Member: bastla
bastla Aug 12, 2009 at 13:38:10 (UTC)
Goto Top
Hallo Andreas!

... und danke Dir für die Anpassung des Titels.

Grüße
bastla
Member: bastla
bastla Aug 13, 2009 at 07:56:31 (UTC)
Goto Top
Hallo Andreas!

Wie gewünscht noch eine kurze Erklärung zum Script:
Durch die Verwendung von "Split()" mit dem Trennzeichen "vbCrLF" (= Windows-Zeilenschaltung) entsteht ein eindimensionales Array, welches in jedem Element eine Zeile (bei einer Leerzeile einen Leerstring) der eingelesenen Textdatei enthält.

Die "For-Each"-Schleife ermöglicht das Abarbeiten aller Array-Elemente, wobei das jeweilige Element in der Schleifenvariable (zB "Suchbegriff") zur Verfügung gestellt wird - Alternative dazu:
For i = 0 To UBound(Text1)
    Suchbegriff = Text1(i)
    ...
Next
Diese Schreibweise ist dann sinnvoll, wenn der Index benötigt wird, um etwa nur eine bestimmte Anzahl von Elementen zu verarbeiten - für die letzten 20 Zeilen hieße es dann etwa
Ab = UBound(Text1) - 19
If Ab < 0 Then Ab = 0
For i = Ab To UBound(Text1)
   ...
In solchen Situationen bringt das Einlesen des Textfiles in das Array nicht nur einen Geschwindigkeitsvorteil, sondern vereinfacht auch die Verarbeitung (da Du dann schon weißt, wieviele Zeilen es insgesamt gibt).

Grüße
bastla
Member: JoshuaTree
JoshuaTree Aug 13, 2009 at 08:45:23 (UTC)
Goto Top
Danke für die Erklärung,

ich wollte mir nun gerade mal die Variable bzw. das Array Text1 mit wscript.echo ausgeben lassen das ging nicht. Warum ? Weil zu groß !?
Und kann man sich die Anzahl der Zeilen auch schon vorher ausgeben lassen wenn man sie schon weiß?

Gruss
Andreas
Member: bastla
bastla Aug 13, 2009 at 09:17:59 (UTC)
Goto Top
Hallo Andreas!
Und kann man sich die Anzahl der Zeilen auch schon vorher ausgeben lassen wenn man sie schon weiß?
Die Zeilenanzahl ist
UBound(Text1) + 1
"UBound()" liefert den höchsten Index des Arrays, und da Arrays in VBS null-basiert sind, gibt es ein Element (Test1(0)) mehr ...
ich wollte mir nun gerade mal die Variable bzw. das Array Text1 mit wscript.echo ausgeben lassen das ging nicht. Warum ?
Da das Array aus mehreren Elementen besteht, kannst Du entweder ein bestimmtes Element, zB die vierte Zeile mit
WScript.Echo Text1(3)
ausgeben, oder Du musst das gesamte Array wieder zu einem einzigen String zusammenfügen - das sähe so aus:
WScript.Echo Join(Text1, vbCrLF)
Wie das Zusammenfügen erfolgt, kannst Du an diesem Beispiel sehen:
WScript.Echo Join(Text1, "[Zeilenende]" & vbCrLF & "[Zeilenanfang]")

Mit einer Schleife kannst Du natürlich auch alle einzelnen Elemente anzeigen lassen:
For i = 0 To UBound(Text1)
    WScript.Echo i, Text1(i)
Next
Grüße
bastla
Member: JoshuaTree
JoshuaTree Aug 13, 2009 at 12:47:02 (UTC)
Goto Top
Wenn ich mir UBound(Text1) + 1 ausgeben lasse bekomme ich 706 zurück in der Liste sind aber nur 705

Und wenn ich mir mit der For-Schleife jedes Element einzeln anzeigen lasse zeigt er mir immer ein Zähler zu hoch an, OK das hängt daran das er bei 0 anfängt zu zählen aber die Gesamtzahl die müßte doch 705 sein oder ?
Member: bastla
bastla Aug 13, 2009 at 12:55:51 (UTC)
Goto Top
Hallo Andreas!

Vermutlich enthält die (für Dich) letzte Zeile am Ende noch eine Zeilenschaltung, wodurch sich für das Ergebnis des Split() noch eine zusätzliche Leerzeile ergibt - entsprechend müsste in der Ausgabe mittels Schleife als letzte Zeile nur der Index (705) aufscheinen ...

Grüße
bastla
Member: JoshuaTree
JoshuaTree Aug 13, 2009 at 13:13:39 (UTC)
Goto Top
hallo Bastla,

du hattest wie immer recht face-smile
Member: JoshuaTree
JoshuaTree Aug 13, 2009 at 14:24:09 (UTC)
Goto Top
Hab noch ein wenig an dem Script rum gebastelt.
Jetzt habe ich mir eine Datei ausgeben lassen wo das Delta rein soll bin echt erschrocken als ich sah wie groß die Datei ist.
Datei = "vergleich.csv"  
PFad = "c:\temp\"  
Set FileSystem = WScript.CreateObject("Scripting.FileSystemObject")  
Set OutPutFile = FileSystem.CreateTextFile(Pfad & Datei, True)

OutPutFile.WriteLine "Name;Verzeichnis"  


Set objFSO = CreateObject("Scripting.FileSystemObject")  
Text1 = Split(objFSO.OpenTextFile("C:\Temp\Dis-User-in-delOU.csv").ReadAll, vbCrLF)  
Text2 = Split(objFSO.OpenTextFile("C:\Temp\ts-Verzeichnisse-die-fehlen.csv").ReadAll, vbCrLF)  





For Each Suchbegriff In Text1


    For Each Zeile In Text2
    	If InStr(1, Zeile, Suchbegriff, 1) Then
            
            
            'i = i + 1  
        Else
        	outputFile.WriteLine  Zeile
            'u = u + 1  
        End If
    Next


    'WScript.Echo "Suchbegriff " & Suchbegriff & " " & i & "x gefunden"  
    'WScript.Echo "Suchbegriff " & Suchbegriff & " " & u & "x nicht gefunden" & vbCrLF  
i = 0
u = 0
Next

wscript.echo "fäddisch"  
Es schreibt 39x pro eintrag aus Text ein in die Datei. Warum er soll doch nur wenn er den eintrag nicht findet.

Grüsse
Andreas
Member: bastla
bastla Aug 13, 2009 at 14:43:14 (UTC)
Goto Top
Hallo Andreas!

Soferne es Dir nur darum geht, alle Zeilen aus Text1, die überhaupt nicht in Text2 enthalten sind, in die "vergleich.csv" zu schreiben, solltest Du Text2 am Stück belassen und es etwa so realisieren:
Datei = "vergleich.csv"  
PFad = "c:\temp\"  

Set objFSO = CreateObject("Scripting.FileSystemObject")  

Text1 = Split(objFSO.OpenTextFile("C:\Temp\Dis-User-in-delOU.csv").ReadAll, vbCrLF)  
Text2 = objFSO.OpenTextFile("C:\Temp\ts-Verzeichnisse-die-fehlen.csv").ReadAll  
Set OutPutFile = objFSO.CreateTextFile(Pfad & Datei, True)

OutPutFile.WriteLine "Name;Verzeichnis"  

For Each Suchbegriff In Text1
    	If InStr(1, Text2, Suchbegriff, vbTextCompare) = 0 Then  	outputFile.WriteLine Suchbegriff
Next

wscript.echo "fäddisch"  
Es genügt übrigens ein "FileSystemObject" pro Script ...

Grüße
bastla
Member: JoshuaTree
JoshuaTree Aug 14, 2009 at 08:06:46 (UTC)
Goto Top
Zitat von @bastla:
Es genügt übrigens ein "FileSystemObject" proScript ...


Moin,

Danke für den Hinweis mit nur einem FSO pro Script das habe ich mich auch schon öfter gefragt aber jetzt weis ich es.

Jetzt funktioniert es das ich nur das Delta bekomme allerdings brauche ich auch die Zeile bwz. deren Inhalt wo er es gefunden hat.
Denn es handelt sich um Verzeichnisse von Usern die Fehlen und um das weiter verarbeiten zu können z.b in eine anderen Script wo dann das Fehlende Verzeichnis angelegt wird.

Gruss
Andreas
Member: bastla
bastla Aug 14, 2009 at 09:12:52 (UTC)
Goto Top
Hallo Andreas!

Da mir der Inhalt der beiden Dateien nicht bekannt ist, zwei Vorschläge:
  • Versuche es mit einem Vertauschen von "Text1" und "Text2" in den Zeilen 6 und 7, und falls das nicht das gewünschte Ergebnis liefert,
  • poste bitte auszugsweise (und anonymisiert) einige Zeilen aus beiden Dateien und das gewünschte Ergebnis ...

Grüße
bastla
Member: JoshuaTree
JoshuaTree Aug 14, 2009 at 09:46:39 (UTC)
Goto Top
Die Datei Dis-User-in-delOU.csv enthält einzeilig Usernamen und zwar User welche bereits gelöscht sind und in entsprechend in eine OU verschoben sind.
Die Datei ts-Verzeichnisse-die-fehlen.csv enthält eine Liste der Userverzeichnisse als UNC-Pfad die generell fehlen. Der Sinn dahinter ist das die Fehlenden Verzeichnisse angelegt werden müssen.
Jedoch die der gelöschten User ausgenommen da die ja gelöscht sind und es gewollt ist das sie kein Ts-Verzeichnis haben.

Noch mach in Kürze.
Text1 enthält ne Liste:
User1
User2
User3
etc.

Text2 enthält ne Liste
\\Verzeichnis\das\UserXY
\\Verzeichnis\von\User1
\\Verzeichnis\Hauptquartier\User3
etc.

Hoffe das war verständlich
face-smile

Gruss
Andreas
Member: bastla
bastla Aug 14, 2009 at 10:11:19 (UTC)
Goto Top
Hallo Andreas!

Mal dauert's lang, dann wieder länger (bis der Groschen fällt) ...

Datei = "vergleich.csv"  
PFad = "C:\temp\"  

Set objFSO = CreateObject("Scripting.FileSystemObject")  

Text1 = Split(objFSO.OpenTextFile("C:\Temp\Dis-User-in-delOU.csv").ReadAll, vbCrLf)  
Text2 = Split(objFSO.OpenTextFile("C:\Temp\ts-Verzeichnisse-die-fehlen.csv").ReadAll, vbCrLf)  
Set OutPutFile = objFSO.CreateTextFile(Pfad & Datei, True)

OutPutFile.WriteLine "Name;Verzeichnis"  

For Each Pfad In Text2
    Username = Mid(Pfad, InStrRev(Pfad, "\") + 1)  
    Anlegen = True
    For Each User In Text1
        If StrComp(User, Username, vbTextCompare) = 0 Then
            Anlegen = False
            Exit For
        End If
    Next
    If Anlegen Then outputFile.WriteLine Username & ";" & Pfad  
Next

WScript.Echo "fäddisch"  

Nur als Randbemerkung: In Batch (bzw direkt von der Kommandozeile) würde sich das Ganze (mit der Einschränkung, dass nur die Pfade ausgegeben werden) reduzieren auf:
findstr /v /i /e /g:"C:\TEMP\Dis-User-in-delOU.csv" "C:\temp\ts-Verzeichnisse-die-fehlen.csv">"C:\temp\vergleich.csv"
bzw ohne die genannte Einschränkung, aber mit Laufzeitnachteilen auf:
for /f "delims=" %i in ('findstr /v /i /e /g:"C:\TEMP\Dis-User-in-delOU.csv" "C:\temp\ts-Verzeichnisse-die-fehlen.csv"') do @>>"C:\temp\vergleich.csv" echo %~nxi;%i
Grüße
bastla
Member: JoshuaTree
JoshuaTree Aug 14, 2009 at 10:16:16 (UTC)
Goto Top
Oh man das ist ja frustrierend, du hast recht an Batch habe ich in meinem Script-Wahn gar nicht gedacht
aber dafür habe ich eine Menge gelernt face-wink

Du hast einen "großen Pott" Kaffee gut

Gruss
Andreas

Nachtrag:
Gerade ausprobiert
Mit Batsch würde es nicht gehen da Batch nach User1 sucht und dort auch mit User15 oder User1234 ein match hätte und das ausgeben würde
Member: bastla
bastla Aug 14, 2009 at 10:33:17 (UTC)
Goto Top
Hallo Andreas!

Nur der Ordnung halber: Da der Oneliner in Batch auch Teilstrings finden sollte, würde ich trotzdem zum VBScript raten ...

Grüße
bastla
Member: JoshuaTree
JoshuaTree Aug 18, 2009 at 08:04:32 (UTC)
Goto Top
Ich bastele immer noch ein bißchen an dem Script rum.
Wollte jetzt selektiert einzelne Objekte aus der cn.txt in die For-Schleife holen
in cn.txt steht jetzt im moment nur zwei Zeilen
CN=B051MM,OU=Users,OU=DE,OU=xxx,DC=eu,DC=xxx,DC=corp
CN=TKY,OU=Users,OU=HQ,OU=xxx,DC=eu,DC=xxx,DC=corp
Jetzt zeigt er mir 14mal OU=xxx in einem PopUp an, warum
Ich hätte erwartet das er mir OU=xxx nur 2x anzeigt da es ja nur 2 Zeilen sind.

Set objFSO = CreateObject("Scripting.FileSystemObject")  



Text1 = Split(objFSO.OpenTextFile("C:\Temp\cn.txt").ReadAll, ",")  



For each Zeile in Text1
wert = Text1(3)
wscript.echo wert

next

Verstehe ich nicht !?

Gruss
Andreas
Member: bastla
bastla Aug 18, 2009 at 10:05:15 (UTC)
Goto Top
Hallo Andreas!

Was Du offensichtlich wolltest, ist:
Set objFSO = CreateObject("Scripting.FileSystemObject")  
Zeilen = Split(objFSO.OpenTextFile("C:\Temp\cn.txt").ReadAll, vbCrLF) 'Zerlege in Zeilen  
For Each Zeile in Zeilen
    Werte = Split(Zeile, ",") 'Zerlege in Werte  
    WScript.Echo Werte(3)
Next
Deine "Zeilen" waren bereits die einzelnen Werte, daher auch die 13 Ausgaben von "OU=xxx"(= 4. Wert aus Zeile 1) ...
Und zum Thema "PopUp": Teste von der Kommandozeile mit
cscript //nologo D:\DeinScript.vbs
Grüße
bastla
Member: JoshuaTree
JoshuaTree Aug 18, 2009 at 12:09:26 (UTC)
Goto Top
Hallo Bastla,

ahhh Verstehe.
Jetzt übergebe ich die Zeile komplett an die Schleife und zerhacke sie dann mit Split und könnte mir die einzelnen Werte herauspicken für die Schleife dich ich weiter verabeiten willl.
Ahhh jetzt ja Danke auch noch mal für den Tip mit cscript.

gruss
Andreas