hausboot
Goto Top

Mehrere Dateien in einer Textdatei per batch oder script zusammenführen

Guten Tag in die Runde der Fachleute.
Ich habe folgendes Problem:
In einem Unterordner liegen Dateien mit verschiedenen Dateinamen z.B. 12345678_0300_1_ra_123_yyy.txt, 12345678_0320_1_ra_123_yyy.txt, 12345678_0340_1_ra_123_yyy.txt usw. Alle Dateien mit dem Dateinameninhalt 0300 sollen erkannt und in eine Datei (12345678_0300_1_rco_123_yyy.txt) geschrieben werden. Das Gleiche ist auch auf die restlichen Dateien (0320, 0340, 0360, 0380, 0400, 0420, 0440, 0460, 0480, usw.) anzuwenden. Der erste Block des Dateinamens (z.B. 12345678) kann unterschiedlich lang sein, hat aber immer gleiche Bezeichnung in dem Dateiordner. Die Angabe im zweiten Block kann variieren z.B 0320, 0321......0340, 0341 usw. Er besteht immer aus vier Ziffern. Die restlichen Blöcke sind immer gleich.
Ziel ist es, die Dateien mit der selben Bezeichnung im Block zwei, zu einer Datei zusammenzuführen und alle Punkte in der neuen Datei mit einem Komma zu ersetzen. Ebenfalls soll der Unterordner (wo die zu bearbeitenden Dateien liegen) variabel ausgesucht werden können z.B. c:\Ordnerx\Unterordner\Dateien, d:\Ordnery\Unterordner\Dateien.

Für Eure Bemühungen im Voraus vielen Dank.

Hausboot

Content-Key: 250454

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

Printed on: April 19, 2024 at 05:04 o'clock

Member: laster
laster Sep 29, 2014 at 15:01:53 (UTC)
Goto Top
Hallo,

zum ersten Punkt schon mal:
type *_0300_*.txt > daten_0300.txt
ren daten_0300.txt 12345678_0300_1_rco_123_yyy.txt

Dann noch die Zeichen ersetzen - gibt es bestimmt Commandline -Tools wie "sed für Windows" oder hier ( Per Batch ein Wort in Einer Textdatei gegen ein anderes ersetzen ).

Gruß
LS
Member: Hausboot
Hausboot Sep 29, 2014 at 15:30:33 (UTC)
Goto Top
Hallo Laster,
Danke für Deinen Beitrag.
Die Dateien, wo der zweite Block identisch ist, sollten automatisch erkannt und zusammengefaßt werden. Deine Lösung bedeutet zuviel Handarbeit.

Gruß
Hausboot
Member: laster
laster Sep 29, 2014 at 15:42:34 (UTC)
Goto Top
na dann halt

@echo off

:: von 320 bis 980 mit Schrittweite 20
for /L %%i IN (320, 20, 980) do call :PROC1 %%i
goto ENDE

:PROC1
set BLK=%1
type *_0%BLK%_*.txt > daten_0%BLK%.txt 
ren daten_0%BLK%.txt 12345678_0%BLK%_1_rco_123_yyy.txt
:: tausche die Zeichen in der Datei ...
goto :EOF

:ENDE

ist weniger 'Handarbeit'
Member: Friemler
Friemler Sep 29, 2014 at 17:16:56 (UTC)
Goto Top
Hallo Hausboot,

anhand dieser beiden Aussagen
Zitat von @Hausboot:

Der erste Block des Dateinamens (z.B. 12345678) kann unterschiedlich lang sein, hat aber immer gleiche Bezeichnung in dem Dateiordner.
und
Zitat von @Hausboot:

Die restlichen Blöcke sind immer gleich.
und den Beispieldateinamen ergibt sich eine Schwierigkeit: Es können nicht mehrere Dateien in dem Verzeichnis existieren, bei denen der zweite Block des Namens gleich ist, da ja schon alle anderen Namensbestandteile gleich sind. Da dem bestimmt nicht so ist (sonst würde Dein Problem nicht existieren), könnte man das jetzt einfach als Missverständnis ignorieren, aber nach welcher Regel wird dann der Name (bzw. der erste Block des Names) der Sammeldatei bestimmt?

Gruß
Friemler
Member: Hausboot
Hausboot Sep 29, 2014 at 17:55:57 (UTC)
Goto Top
Guten Abend Friemler,

Block eins ist immer gleich im jeweiligen Unterordner. Block zwei ist variabel. Block drei und vier sind gleich. Block fünf und sechs sind variabel.

Z.B. Unterordner 1
Datei 12345678_0300_1_ra_123_yyy.txt
Dateien sind z.B neun mal vorhanden mit anderen Werten in Block fünf und sechs.
Datei 12345678_0320_1_ra_123_yyy.txt
Dateien sind z.B neun mal vorhanden mit anderen Werten in Block fünf und sechs.

Unterordner 2 (wird gesondert betrachtet).
Datei 34567812_0300_1_ra_123_yyy.txt

Die zusammengefasste Datei soll im Beispiel 1
In 12345678_0300_1_rco_123_yyy.txt , 12345678_0320_1_rco_123_yyy.txt gespeichert werden.

Die im Beispiel zwei in 34567812_0300_1_rco_123_yyx.txt

Wichtig ist, dass Block eins und zwei bei der Speicherung die gleiche Bezeichnung haben wie die Ursprungsdatei.

Ich hoffe, dass es so etwas verständlicher ist.

Gruß
Hausboot
Member: Friemler
Friemler Sep 29, 2014 at 18:16:57 (UTC)
Goto Top
Hallo Hausboot,

OK, das ist schon besser, aber noch nicht perfekt:

Zitat von @Hausboot:

Block fünf und sechs sind variabel.
und
Zitat von @Hausboot:

Datei 12345678_0300_1_ra_123_yyy.txt
Dateien sind z.B neun mal vorhanden mit anderen Werten in Block fünf und sechs.
...
Die zusammengefasste Datei soll in
12345678_0300_1_rco_123_yyy.txt ... gespeichert werden.

Da Block fünf und sechs variabel sind, müssen sie im Namen der Zieldatei entweder weggelassen werden oder ich benötige eine Bildungsregel für die beiden Blöcke.

Gruß
Friemler
Member: Hausboot
Hausboot Sep 29, 2014 at 18:34:23 (UTC)
Goto Top
Hallo Friemler,
Die beiden letzen Blöcke können auch weggelassen werden.

Gruß

Hausboot
Member: Hausboot
Hausboot Sep 29, 2014 at 18:39:31 (UTC)
Goto Top
Hallo Laster,

Danke für die Mühe. Wenn ich die Batchdatei starte, werden zwei leere Dateien (daten_0320 und 12345678_0320) erstellt.
Gruß
Hausboot
Member: colinardo
colinardo Sep 29, 2014, updated at Sep 30, 2014 at 10:31:31 (UTC)
Goto Top
Zitat von @Hausboot:
Die beiden letzen Blöcke können auch weggelassen werden.
Moin Hausboot,
mit Powershell liefe das auf einen Einzeiler hinaus face-wink
dir 'C:\ordner' -Filter *.txt | ?{$_.Name -match '^[^_]+_\d{4}'} | %{(gc $_.FullName | Out-String).Replace(".",",") | Add-Content -Path ($_.DirectoryName + "\" + $matches + ".txt")}  
Im Beispiel wird in dem Ordner nur auf Dateien mit der Endung *.txt gefiltert.

Die Ausgabedateien im jeweiligen Ordner sehen dann so aus:
12345678_0300.txt
12345678_0320.txt
....

Grüße Uwe
Member: Friemler
Friemler Sep 29, 2014, updated at Sep 30, 2014 at 06:40:41 (UTC)
Goto Top
Hallo Hausboot,

OK, here we go.

Es ist allerdings eine VBScript-Lösung daraus geworden, da mir Batchscript dafür suboptimal erschien.

Option Explicit


Const ForReading   = 1
Const ForWriting   = 2
Const ForAppending = 8


Dim objFSO, objRegEx, colMatches, dicOutStreams
Dim objFile, objInStream, objOutStream
Dim strSourcePath, strFileGroup, strOutFileName, strOutFilePath


If WScript.Arguments.Count > 0 Then
  Set objFSO          = CreateObject("Scripting.FileSystemObject")  
  Set dicOutStreams   = CreateObject("Scripting.Dictionary")  
  Set objRegEx        = New RegExp

  strSourcePath       = WScript.Arguments(0)
  
  objRegEx.Pattern    = "^([^_]+)_([0-9]+)_([^_]+)_(ra)_([^_]+)_([^\.]+)\.(txt)$"  
  objRegEx.IgnoreCase = True

  If objFSO.FolderExists(strSourcePath) Then
    For Each objFile In objFSO.GetFolder(strSourcePath).Files
      Set colMatches = objRegEx.Execute(objFile.Name)

      If colMatches.Count > 0 Then
        If colMatches(0).SubMatches.Count > 0 Then
          strFileGroup = colMatches(0).SubMatches(1)
          
          If Not dicOutStreams.Exists(strFileGroup) Then
            strOutFileName   = objRegEx.Replace(objFile.Name, "$1_$2_$3_rco.$7")  
            strOutFilePath   = objFSO.BuildPath(strSourcePath, strOutFileName)
            Set objOutStream = objFSO.CreateTextFile(strOutFilePath, True)
            Call dicOutStreams.Add(strFileGroup, objOutStream)
          Else
            Set objOutStream = dicOutStreams(strFileGroup)
          End If
          
          Set objInStream = objFile.OpenAsTextStream(ForReading)
          Call objOutStream.Write(objInStream.ReadAll)
          objInStream.Close
        End If
      End If
    Next

    For Each objOutStream In dicOutStreams.Items
      objOutStream.Close
    Next
  Else
    WScript.Echo "Das angegebene Verzeichnis existiert nicht."  
  End If
Else
  WScript.Echo "Bitte geben Sie das Verzeichnis mit den Quelldateien an."  
End If

Das Script z.B. als "MergeFiles.vbs" speichern. Das Script kann dann folgendermaßen aufgerufen werden:
cscript /nologo "Pfad-zum-Script\MergeFiles.vbs" "Pfad-zum-Verzeichnis-mit-den-Dateien"

Alternativ kann auch per Drag&Drop das Icon des Verzeichnisses auf dem Icon des Scripts fallengelassen werden. Das funktioniert auch mit einer Verknüpfung auf die Scriptdatei.

Gruß
Friemler
Member: Hausboot
Hausboot Sep 29, 2014 at 19:09:24 (UTC)
Goto Top
Vielen Dank an Alle. Ich werde die Lösungsvorschläge morgen testen und Euch berichten.

Gruß

Hausboot
Member: Hausboot
Hausboot Sep 30, 2014 at 10:01:53 (UTC)
Goto Top
Hallo Friemler,

danke für deine Mühe.
Das Script "MergeFiles.vbs lässt sich bei mir mit dem angegebenen Script (cscript /nologo "C:\Users\Werner\Desktop\MergeFiles.vbs" "C:\Users\Werner\Patternt" )nicht aufrufen.
Ich erhalte eine Fehlermeldung Zeile 1, Zeichen 9 Fehler Syntaxfehler, Code 800A03EA. Was mache ich falsch?

Gruß

Hausboot
Member: Friemler
Friemler Sep 30, 2014 at 10:15:42 (UTC)
Goto Top
Moin Hausboot,

anscheinend ist bei der Übernahme des Quelltextes etwas schief gegangen. Um das auf jeden Fall zu vermeiden, klicke in der rechten oberen Ecke der Codebox (blau-weiß gestreiftes Feld mit dem Quellcode) auf "Quelltext" und kopiere den Scriptcode aus dem sich dann öffnenden Fenster in einen Texteditor Deiner Wahl. Dann "Speichern als..." mit der Dateierweiterung vbs. Abtippen oder das Kopieren direkt aus der Codebox führt regelmäßig zu Fehlern.

Gruß
Friemler
Member: Hausboot
Hausboot Sep 30, 2014 at 10:17:29 (UTC)
Goto Top
Hallo Uwe,

ich habe folgenden Text (dir "C:\Users\Werner\patternt" -Filter *.txt | ?{$_.Name -match '^[^_]+_\d{4}'} | %{(gc $_.FullName | Out-String).Replace(".",",") | Add-Content -Path ($_.DirectoryName + "\" + $matches + ".txt")} in die vbs-Datei eingegeben.
Folgende Fehlermeldung wird beim Starten des Scipts angezeigt: Zeile 1, Zeichen 46, Fehler: Ungültiges Zeichen, Code 800A0408. Was könnte den Fehler verursachen?

Gruß

Hausboot
Member: colinardo
Solution colinardo Sep 30, 2014 updated at 10:54:29 (UTC)
Goto Top
Zitat von @Hausboot:
ich habe folgenden Text (dir "C:\Users\Werner\patternt" -Filter *.txt | ?{$_.Name -match '^[^_]+_\d{4}'} |
%{(gc $_.FullName | Out-String).Replace(".",",") | Add-Content -Path ($_.DirectoryName + "\" +
$matches + ".txt")} in die vbs-Datei eingegeben.
Folgende Fehlermeldung wird beim Starten des Scipts angezeigt: Zeile 1, Zeichen 46, Fehler: Ungültiges Zeichen, Code
800A0408. Was könnte den Fehler verursachen?
Das ist kein VBS, sondern Powershell !! Du gibst es also entweder direkt in eine Powershell-Konsole(powershell.exe) ein. Wichtige Hinweise s. Anleitung unten:

back-to-topAnleitung: Wie starte ich Powershell-Scripte
  • Zuerst speichert man den Code in einer Textdatei mit der Endung .ps1.
  • Wenn man zum ersten mal Powershell-Scripte ausführt, musst man einmalig vorher noch das Ausführen von Scripten im User-Account freischalten. Dazu öffnet man eine Powershell-Konsole und gibt dort den Befehl Set-ExecutionPolicy RemoteSigned -Force ein. Um diese Policy für alle User auf dem Rechner zu setzen muss man diesen Befehl in einer Powershell-Konsole mit Admin-Rechten starten. Noch ein Hinweis für 64-Bit-Systeme: Hier sollte sowohl für die 32bit und 64Bit Variante der Powershell die Policy in einer Admin-Konsole gesetzt werden: Set-ExecutionPolicy RemoteSigned -Force; start-job { Set-ExecutionPolicy RemoteSigned -Force } -RunAs32
  • Jetzt kann das Powershell-Script wie weiter unten erläutert in einer Powershell-Konsole oder aus einer CMD-Fenster heraus ausgeführt werden. Wer lieber mit der Maus arbeitet macht einen Rechtsklick auf die Script-Datei und wählt: Mit Powershell ausführen.
  • Alternativ lässt sich ein Script auch ohne das globale Ändern der ExecutionPolicy ausführen indem man die Policy als Parameter auf der Kommandozeile mitgibt:
powershell.exe -ExecutionPolicy RemoteSigned -File "C:\Pfad\Script.ps1"
back-to-topStarten eines Scriptes in einer Powershell-Konsole
Immer den kompletten Pfad zum Script angeben, und wenn er Leerzeichen beinhaltet in Anführungszeichen einschließen:
"C:\Pfad\script.ps1"
Liegt das Script im selben Verzeichnis in dem man sich gerade befindet, kann man es auch so abkürzen:
.\script.ps1
back-to-topStarten von PS-Scripten aus Batch und Kommandozeilen heraus:
Hier gibt es unterschiedliche Methoden, je nach Anforderungen gibt es hier einige Besonderheiten vor allem bei Leerzeichen in Pfaden zu beachten!
Der einfachste Aufruf sieht hier so aus:
powershell.exe -File "C:\Pfad\Script.ps1"
Wenn man dem Script Parameter übergeben möchte:
powershell.exe -File "C:\Pfad\Script.ps1" "Parameter 1" "Parameter 2"
Wenn man "benannte" Parameter übergeben möchte (die einfachen Hochkommas um den Scriptpfad werden benötigt wenn er Leerzeichen beinhaltet):
powershell.exe -command "&'C:\Pfad\Script.ps1' -par1 'Wert1' -par2 'Wert2'"
Man kann auch mehrere Scripte hintereinander ausführen lassen:
powershell.exe -command "&'C:\Pfad\Script1.ps1';&'C:\Pfad\Script2.ps1'"
Weitere Parameter zeigt einem ein powershell -? in einer Konsole an.
back-to-topStarten von PS-Scripten in der Aufgabenplanung (Taskplaner)
In der jeweiligen Aktion unter "Programm/Script" trägt man powershell.exe ein und unter "Argumente hinzufügen (optional)" trägt man wie oben geschrieben alles was hinter powershell.exe kommt ein - also z.B. -File "C:\Pfad\Script.ps1" "Parameter 1" "Parameter 2"
Member: Hausboot
Hausboot Sep 30, 2014 at 10:24:58 (UTC)
Goto Top
Hallo Friemler,

ich habe es genau so gemacht (Datei MergeFiles.vbs), wie Du es beschrieben hast. Lediglich der Aufruf der Datei funktioniert nicht. Wenn ich per Drag&Drop das Icon des Verzeichnis auf das Icon ds Scripts fallen lasse, ändert sich ebenfalls nichts.

Gruß

Hausboot
Member: Friemler
Friemler Sep 30, 2014 updated at 10:32:33 (UTC)
Goto Top
Hallo Hausboot,

dann poste bitte den Inhalt Deiner Scriptdatei unter Verwendung von Codetags. Syntaxfehler heißt, Du hast den Quelltext irgendwie falsch übernommen. Ach ja, den Quellcode nicht mit Word speichern und nachher umbenennen. Das ist dann kein reines Textformat und der VBScript-Interpreter kann die Datei nicht "verstehen".

Gruß
Friemler
Member: Friemler
Friemler Sep 30, 2014 updated at 10:50:27 (UTC)
Goto Top
[OFF TOPIC]

Moin Uwe,

die obige (sehr gute) "Wie starte ich PowerShell-Scripte?"-Anleitung hast Du ja anscheinend schon irgendwo dauerhaft gespeichert. face-wink

Du könntest noch ergänzen, dass man PS-Scriptdateien auch mit
powershell.exe -ExecutionPolicy RemoteSigned -File "C:\Pfad\Script.ps1" "Parameter 1" "Parameter 2"
starten kann, ohne die Execution Policy vorher ändern zu müssen. Das macht es Newbies etwas leichter, einen kurzen Script-Test auszuführen.

Gruß
Friemler

[/OFF TOPIC]
Member: colinardo
colinardo Sep 30, 2014 updated at 10:51:32 (UTC)
Goto Top
Hi Friemler,
Zitat von @Friemler:
Du könntest noch ergänzen, dass man PS-Scriptdateien auch mit
yip, hatte ich noch vergessen, Danke für den Hinweis, werde ich sofort nachtragen face-smile

Grüße Uwe
Member: Hausboot
Hausboot Sep 30, 2014 at 11:25:19 (UTC)
Goto Top
Hallo Carinardo,

danke für den Hinweis. Jetzt funktioniert es.
Wie kann man es lösen, dass die Pfade zu den bearbeitenden Dateien nicht mehr statisch, sonder per Eingabefenster ausgewählt werden können. Ist sowas möglich?

Gruß

Hausboot
Member: colinardo
colinardo Sep 30, 2014 updated at 11:57:37 (UTC)
Goto Top
Zitat von @Hausboot:
danke für den Hinweis. Jetzt funktioniert es.
Wie kann man es lösen, dass die Pfade zu den bearbeitenden Dateien nicht mehr statisch, sonder per Eingabefenster
ausgewählt werden können. Ist sowas möglich?
klar, indem du im Script Parameter verwendest und dann auf der Kommandozeile den Pfad übergibst:
param(
  [string]$path
)
dir $path -Filter *.txt | ?{$_.Name -match '^[^_]+_\d{4}'} | %{(gc $_.FullName | Out-String).Replace(".",",") | Add-Content -Path ($_.DirectoryName + "\" + $matches + ".txt")}  
und dann der Aufruf wie oben in der Anleitung beschrieben:
powershell.exe -File "C:\Pfad\Script.ps1" "C:\deinpfad"

Grafische Sachen sind selbstverständlich auch möglich, da Powershell auf .NET basiert und das ganze NET-Framework nutzen kann.

Beispiel mit einem FolderBrowserDialog zur Auswahl des Pfades:
Add-Type -AssemblyName System.Windows.Forms
$dlg = new-object System.Windows.Forms.FolderBrowserDialog
if($dlg.ShowDialog() -eq [System.Windows.Forms.DialogResult]::OK){
  dir $dlg.SelectedPath -Filter *.txt | ?{$_.Name -match '^[^_]+_\d{4}'} | %{(gc $_.FullName | Out-String).Replace(".",",") | Add-Content -Path ($_.DirectoryName + "\" + $matches + ".txt")}    
}
Grüße Uwe
Member: Hausboot
Hausboot Sep 30, 2014 at 15:21:37 (UTC)
Goto Top
Hallo Uwe,

meine letzte Frage. Wo füge ich den von Dir geposteten Quelltext ein? Ich kann zwar einen Ordner auswählen, weiß aber dann nicht mehr weiter.

Gruß

Hausboot
Member: colinardo
Solution colinardo Sep 30, 2014 updated at 15:59:05 (UTC)
Goto Top
Zitat von @Hausboot:

Hallo Uwe,

meine letzte Frage. Wo füge ich den von Dir geposteten Quelltext ein? Ich kann zwar einen Ordner auswählen, weiß
aber dann nicht mehr weiter.

hä ???
das sind jeweils eigenständige Scripte die komplett sind ...
Member: Hausboot
Hausboot Sep 30, 2014 at 15:59:09 (UTC)
Goto Top
Ich Danke allen, die zur Lösung meines Problems beigetragen haben.

Gruß

Hausboot