overdue
Goto Top

Batch für Textdatei, bestimmte Zeile suchen und ändern

Hallo,

ich weiß das ich unter Google etliche ähnliche Problemstellungen finde. Ich habe sie auch fast alle gelesen und auch etwas herum probiert. Nur leider reichen meine Batch Kenntnisse (habe erst die Tage mit Tutorials angefangen) nicht aus um das Ganze zum Laufen zu bringen.

Hier also mein Problem/Wunsch:

Ich habe mehrere Textdateien ( z.B.: Test1.txt, Test2.txt, Test3. usw.) welche Tabellen enthalten. Diese Dateien haben alle den gleichen Aufbau, unterscheiden sich nur durch bestimmte Werte. Da die Tabellen relativ groß und kompliziert sind, reicht zur Lösung meines Problems auch vereinfachte Form, z.B.:

Wert Bezeichnung

123 Geschwindigkeit
456 Anzahl
789 Preis

Jetzt möchte ich, dass in jeder Datei nur eine bestimmte Zeile gesucht und bearbeitet wird, in der z.B. die Bezeichnung ‘‘Anzahl“ steht. In dieser Zeile sollen z.B. nur die ersten drei Werte geändert werden die am Anfang dieser Zeile stehen, in diesem Falle 456 in z.B. 888.

Wert Bezeichnung

123 Geschwindigkeit
888 Anzahl
789 Preis

am besten Wäre es, wenn die Ausgangsdateien einfach geändert werden, also weder gelöscht noch neue Dateien erstellt werden. Jedoch wäre die Erstellung neuer Dateien nicht so tragisch.

Also zusammenfassend:

Parameter: "Bezeichnung", "neuer Wert"

Zeilen der Textdateien nach Bezeichnung durchsuchen, die ersten drei Stellen der bestimmten Zeile durch „neuer Wert“ ersetzen.

Wie gesagt, ich habe schon einige ähnliche Problemstellungen und Lösungen gefunden, wie z.B. das Ändern einer ganzen Zeile. Jedoch ist mir diese Suche am Anfang nach der Bezeichnung sehr wichtig sowie, dass nur ein bestimmter Teil der Zeile (hier die ersten Ziffern) geändert wird.

Ich hoffe ich habe alles soweit verständlich erklärt.

Wäre es wirklich dankbar wenn ihr mir etwas helfen könntet!

Lukas

Content-Key: 175840

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

Ausgedruckt am: 29.03.2024 um 14:03 Uhr

Mitglied: 60730
60730 05.11.2011 um 19:11:54 Uhr
Goto Top
moin,

am besten Wäre es, wenn die Ausgangsdateien einfach geändert werden, also weder gelöscht noch neue Dateien erstellt werden.

Naja -am besten wäre es - wenn es anders gehen würde zu Testzwecken immer neu schreiben statt zu ändern.
Aber Streng genommen, kann man(n) keine Dateien ändern, nur auslesen; Verarbeiten und neuschreiben.

Wie gesagt, ich habe schon einige ähnliche Problemstellungen und Lösungen gefunden, wie z.B. das Ändern einer ganzen Zeile.
  • Hüstel, wenn die originalzeile aus
456 Anzahl
besteht, und die gewünschte
888 Anzahl

Dann ist das doch die ganze Zeile.

Vorschlag meinerseits - du hast einige Treffer gefunden - welche?
Und wo hängt es?
Du schreibst die ganze Zeit was von Tabellen - sind das immer mit Leerzeichen getrennte Werte?
Willst du immer Die Zeile mit Anzahl ändern?

Gruß
Mitglied: bastla
bastla 05.11.2011, aktualisiert am 18.10.2012 um 18:49:01 Uhr
Goto Top
Hallo Overdue und willkommen im Forum!

Ersetzen hätten wir aktuell gerade hier in Arbeit - auf Basis des aktuellen Ansatzes von jeb-the-batcher und Deines Wunsches nach Übergabe per Parameter könnte das etwa so aussehen:
@echo off & setlocal
set "Datei=%~1"  
set "Bez=%~2"  
set "Neu=%~3"  
set "Anz=%~4"  

set "Bak=%temp%\Bak.txt"  
move "%Datei%" "%Bak%"  
setlocal DisableDelayedExpansion
(
  for /f "delims=" %%i in ('findstr /n "^" "%Bak%"') do (  
    set "Line=%%i"  
    setlocal EnableDelayedExpansion
    set "Line=!Line:*:=!"  
    echo !Line!|findstr /e /c:" %Bez%">nul && (set "Line=%Neu%!Line:~%Anz%!")  
    echo(!Line!
    endlocal
  )
)>"%Datei%"  
del "%Bak%"  
In diesem Fall wären 4 Parameter zu übergeben:
  • die zu bearbeitende Datei,
  • die zu suchende Bezeichnung (für die vorausgesetzt wird, dass sie nach einem Leerzeichen am Zeilenende steht),
  • der neue Wert und
  • die Anzahl von Zeichen am Beginn der Zeile, die durch den neuen Wert ersetzt werden sollen

Der Aufruf könnte also etwa so erfolgen:
Ersetze.cmd "D:\Irgendein Ordner\Test1.txt" Anzahl 888 3
Eine kürzere (aber weniger übersichtliche) Fassung käme auch ohne eigens gesetzte Variablen aus:
@echo off & setlocal

set "Bak=%temp%\Bak.txt"  
move %1 "%Bak%"  
setlocal DisableDelayedExpansion
(
  for /f "delims=" %%i in ('findstr /n "^" "%Bak%"') do (  
    set "Line=%%i"  
    setlocal EnableDelayedExpansion
    set "Line=!Line:*:=!"  
    echo !Line!|findstr /e /c:" %~2">nul && (set "Line=%~3!Line:~%~4!")  
    echo(!Line!
    endlocal
  )
)>%1
del "%Bak%"  
Grüße
bastla
Mitglied: Overdue
Overdue 06.11.2011 um 17:21:42 Uhr
Goto Top
Hallo nochmal,

Danke erstmals für die Willkommensgrüße und ganz besonderen Dank an die bisher gepostete Lösung. Ich habe den ersten Vorschlag ausprobiert und er funktioniert auch.
Jetzt kommt aber das "Jedoch", denn die Textdateien haben mehre Spalten, also die gesuchte Bezeichnung steht nicht am Ende der Zeile. Zudem geht es auch um die Veränderung mehrere Dateien gleichzeitig.

Ich beschreibe mein Problem/Wunsch am besten mal ganz speziell:

Es geht um Input Dateien für das Programm FAST, das zur Berechnung von Windkraftanlagen dient. Dieses Programm berechnet nacheinander mehrere dieser Dateien mit entsprechend geänderten Werten.


Ich habe hier einen Link zu einer dieser Datei.:

http://wind.nrel.gov/public/ARobertson/FAST/Training/Simulations/Offsho ...

Wie ihr seht, handelt es sich nicht um eine *.txt- sondern um *.fst-Datei, diese sind aber meiner Meinung nach gleich formatiert.

Die Werte, die geändert werden sollen findet ihr in der ersten Spalte, und die Bezeichnung in der zweiten.

z.B. Zeile 10.:

630.0 TMax - Total run time (s)


"TMax" ist hier die Bezeichnung nach der gesucht wird, und der "630.0" der Wert, der für alle Dateien geändert werden soll.

z.B.:

560.0 TMax - Total run time (s)


Der Name der Dateien ist beliebig, können also z.B.: test1.fst, test2.fst usw. heißen.
Die Parameterabfrage bei Aufruf ist wirklich sehr gut und vollkommen ausreichend. Wie gesagt, die Bearbeitung mehrerer Dateien ist notwendig.

Vielen Dank nochmal für eure Mühe, ich will hier auch nicht einfach nur mein Problem gelöst bekommen, sondern möchte auch etwas dabei lernen, damit ich so etwas in Zukunft auch selbst bewältigen kann. Derzeit versuche ich den ersten Vorschlag zu verstehen, was mir jedoch noch nicht wirklich gelingt. Besteht die Möglichkeit auch Verständnisfragen zu stellen?

P.S.: Gibt es hier auch eine "Spende"-Funktion?

Viele Grüße

Lukas
Mitglied: bastla
bastla 06.11.2011, aktualisiert am 18.10.2012 um 18:49:01 Uhr
Goto Top
Hallo Overdue!

Die verlinkte "fst"-Datei ist eine Textdatei, deren Spalten auf Basis der Zeichenanzahl entstehen - bei direktem Eintrag der Parameter (zum leichteren Testen, aber auch grundsätzlich als Option; bitte vor allem den Wert für "Bez" genau - am besten per c&p aus der Originaldatei - erfassen) ließe sich der Ansatz von oben zunächst für eine Datei eigentlich unverändert übernehmen:
@echo off & setlocal
set "Datei=%~1"  
set "Bez=TMax        - Total run time (s)"  
set "Neu= 560.0"  

set /a Anz=0 & set "Dummy=%Neu%"  
:Loop
set /a Anz+=1
set "Dummy=%Dummy:~1%"  
if defined Dummy goto :Loop

set "Bak=%temp%\Bak.txt"  
move "%Datei%" "%Bak%"  
setlocal DisableDelayedExpansion
(
  for /f "delims=" %%i in ('findstr /n "^" "%Bak%"') do (  
    set "Line=%%i"  
    setlocal EnableDelayedExpansion
    set "Line=!Line:*:=!"  
    echo !Line!|findstr /e /c:" %Bez%">nul && (set "Line=%Neu%!Line:~%Anz%!")  
    echo(!Line!
    endlocal
  )
)>"%Datei%"  
del "%Bak%"  
Hier müsste nur noch die entsprechende Datei (auch per Drag & Drop möglich) übergeben werden. Sollen nun mehrere Dateien auf die selbe Art verändert werden, genügt eine zusätzliche Schleife:
@echo off & setlocal
set "Ordner=D:\Der Ordner mit den fst-Dateien"  
set "Bez=TMax        - Total run time (s)"  
set "Neu= 560.0"  

set /a Anz=0 & set "Dummy=%Neu%"  
:Loop
set /a Anz+=1
set "Dummy=%Dummy:~1%"  
if defined Dummy goto :Loop

set "Bak=%temp%\Bak.txt"  

pushd "%Ordner%"  
for /f "delims=" %%d in ('dir /b /a-d *.fst') do (  
  echo Verarbeite: %%d
  move "%%d" "%Bak%"  
  setlocal DisableDelayedExpansion
  (
    for /f "delims=" %%i in ('findstr /n "^" "%Bak%"') do (  
      set "Line=%%i"  
      setlocal EnableDelayedExpansion
      set "Line=!Line:*:=!"  
      echo !Line!|findstr /e /c:" %Bez%">nul && (set "Line=%Neu%!Line:~%Anz%!")  
      echo(!Line!
      endlocal
    )
  )>"%%d"  
)
del "%Bak%"  
popd
Beide Ansätze sind (weitgehend) ungetestet ...

Kurz zum Ablauf:
Die äußere Schleife übernimmt aus dem Inhaltsverzeichnis ("dir /b /a-d *.fst") des per "pushd" zum aktuellen Ordner gemachten %Ordner% jede einzelne Datei in die Schleifenvariable %%d und führt damit die folgenden Verarbeitungsschritte durch:
  • Verschieben der Datei in eine Temporärdatei %Bak% (= Entfernen der Datei aus dem aktuellen Ordner bei gleichzeitigem Überschreiben einer bereits vorhandenen Temp-Datei)
  • zeilenweises Einlesen der Temporärdatei (Genaueres dazu hat Beitrag beschrieben) und
  • Ersetzen jener Zeile, welche mit der vorgegebenen Bezeichnung endet (aus Sicherheitsgründen, falls etwa eine Bezeichnung auch Teil einer anderen Bezeichnung wäre, wird damit der Suchbegriff genauer festgelegt), durch eine neu zusammengesetzte Zeile mit den Bestandteilen %Neu% (= neuer Wert) + alte Zeile nach der vorgegebenen Zeichenanzahl (also in diesem Fall ab dem 7. Zeichen) - %Neu% muss daher in der entprechenden Länge (inkl. Leerzeichen davor) angegeben werden
  • Schreiben jeder Zeile in die (neu erstellte) Datei (%%d)
Nach Abarbeitung aller Dateien wird die letzte Temp-Datei gelöscht und das "pushd" (der Ordnung halber) mit "popd" rückgängig gemacht.

Noch als Anmerkung: Bei Verwendung von zB VBScript ließe sich die Verarbeitung um einiges beschleunigen ...
Besteht die Möglichkeit auch Verständnisfragen zu stellen?
Aber gerne ...

Grüße
bastla

P.S.: Spenden kannst Du zwar hier nix, aber in Fall des Falles findest Du sicher eine Möglichkeit, jemandem zu helfen ... face-smile

[Edit] Ergänzung: In beiden Varianten wird die Anzahl der zu ersetzenden Zeichen aus %Neu% ermittelt [/Edit]
Mitglied: Overdue
Overdue 07.11.2011 um 08:25:56 Uhr
Goto Top
Wow, das ist alles schon mal super! Konnte in allen Dateien schon mal die Timesteps (DT) ändern und weiter rechnen. Vielen vielen Dank bastla!!
Ich konnte auch andere Input Dateien (andere Dateiendung aber fast gleicher Aufbau) dadurch verändern.

Es kommt lediglich zu folgenden Vorkommnissen, die nicht weiter kritisch sind:

Wenn eine bestimmte Anzahl von bearbeiteten Dateien erreicht wird, erscheint die Meldung "maximum setlocal recursion level reached" und in allen danach bearbeiteten Dateien wird die erste Zeile durch "!Line!" ersetzt. Die macht dem Programm FAST derweilen nichts aus, zu dem muss ich auch nicht immer so viele Dateien auf einmal bearbeiten. Momentan sind es 56.

Es wird eine weitere Datei ohne Dateiendung in den vorgegebenen Ordner erzeugt, diese Datei heisst einfach nur "0]" und beinhaltet (wenn ich sie mit dem Editor öffne) die Zeile
"9998 TEC_NPol - Number of poles [even integer (-) [used only when VSContrl=0 and GenModel=2]" aus der Input Datei (*.fst). Die Zeile bleibt in der Input Datei bestehen, es ist auch egal welchen Wert ich ändern möchte, diese Datei hat immer diesen Inhalt. Auch nicht weiter schlimm.


Was etwas gravierender ist, ist Folgendes:

Manche Zeilen, also Werte, lassen sich einfach nicht ändern. Ich habe etwas herum probiert und glaube den Ursprung des Problems gefunden zu haben. Ich denke, es liegt daran, dass die Zeile gesucht wird, die nach der vorgegebenen Bezeichnung endet.


Als Beispiel, diese Zeile (also ihr Wert am Anfang) lässt sich nicht ändern:

115.926E3 HubIner - Hub inertia about rotor axis [3 blades] or teeter axis [2 blades] (kg m^2)

denn es gibt mehre Zeilen die mit "(kg m^2)" enden.

ändere ich die Zeile in der zu bearbeiteten Datei vorher um (mit einer Zeichenfolge die sonst nicht weiter vorkommt), und kopiere sie in meine Batch, funktioniert es.

Zum Beispiel so:

115.926E3 HubIner - Hub inertia about rotor axis [3 blades] or teeter axis [2 blades]333


Ich habe nur leider keine Ahnung wie ich das beheben soll, zunächst muss ich mit meinen neuen Werten weiter rechnen. Danach werde ich mich intensiver damit auseinandersetzen, damit ich dieses Programm auch auf ähnliche Problemstellungen übertragen kann. Könntest du mir bei auch der Lösung dieses Problemes behilflich sein? Ich steige nämlich nicht ganz, wieviele Stellen hier von hinten nun betrachtet werden, bzw. wie das abläuft.

Du sagst dass man dies mit VBScript schneller rechnen kann. Meinst du dass ich mich in Zukunft, für solche Arbeiten, eher damit auseinander setzen sollte anstatt mit Batch? Oder etwas anderes? Ich finde Batch relativ praktisch, da man keine weitere Software benötigt bzw. sie nichts kostet.

Viele Grüße

Lukas
Mitglied: bastla
bastla 07.11.2011 um 10:43:19 Uhr
Goto Top
Hallo Overdue!

Nur mal kurz zum Thema "maximum setlocal recursion level reached": Verschiebe bitte die Zeile 18 vor die Zeile 15 ...
Die Sonderzeichenproblematik (wegen "^") wäre ein weiterer Grund, auf VBScript zu setzen - ich stelle später am Tag einen Vorschlag rein ...

Grüße
bastla
Mitglied: bastla
bastla 07.11.2011 um 15:45:42 Uhr
Goto Top
Hallo Overdue!

Wie versprochen eine Version, die deb Ersetzungsvorgang per VBScrpt (vom Batch selbst erzeugt) vornimmt:
@echo off & setlocal
set "Ordner=D:\Der Ordner mit den fst-Dateien"  
set "Bez=TMax        -"  
set "Neu= 560.0"  
set "Breite=12"  

set "R=%temp%\Replace.vbs"  
 >%R% echo Set fso=CreateObject("Scripting.FileSystemObject"):Set A=WScript.Arguments:T=fso.OpenTextFile(A(0)).ReadAll  
>>%R% echo Set rE=New RegExp:rE.Pattern="(.{12})("^&A(1)^&")":fso.CreateTextFile(A(0)).Write rE.Replace(T,Left(A(2)^&Space(%Breite%),%Breite%)^&"$2")  
pushd "%Ordner%"  
for /f "delims=" %%d in ('dir /b /a-d *.fst') do (  
  echo Verarbeite: %%d
  cscript //nologo %R% "%%d" "%Bez%" "%Neu%"  
)
popd
Auch in dieser Version würde ich (aus Sicherheitsgründen) etwas mehr als nur die gewünschte Bezeichnung angeben (im Beispiel oben bis zum "-" am Ende der Spalte 2) - gesucht wird hier allerdings (auf Basis Deiner Beispieldatei und im Gegensatz zur Batchvariante) unmittelbar im Anschluss an die erste Spalte (deren Breite in Zeichen durch die Variable %Breite% vorgegeben werden muss).

Der neue Wert muss die gewünschte Anzahl an führenden Leerzeichen enthalten (zum Auffüllen der Spalte werden automatisch die auf %Breite% fehlenden Zeichen in Form von Leerzeichen hinzugefügt).

Weiterer Unterschied: Es wird "in der Datei" ersetzt, also ohne Erzeugung einer Temp-Datei unmittelbar die Ausgangsdatei verändert.

Grüße
bastla
Mitglied: Overdue
Overdue 09.11.2011 um 11:35:34 Uhr
Goto Top
Das klappt bisher reibungslos! Vielen vielen Dank. Damit hast du mich schon ein gutes Stück weiter gebracht. Obwohl ich mittlerweile gar nix mehr verstehe face-smile Aber ich merke, dass es auch für ein großer Vorteil wäre so etwas zu können. Ich hoffe es hat nicht allzu viel Mühe gemacht.

Nochmal zu meiner Frage: Was meinst du, auf welche Programmiersprachen ich mich für soclche Dinge konzentrieren sollte? Ich habe den Eindruck dass ich hier bei die Möglichkeiten von Batch überschreite, jedoch habe ich gelesen, das VBScript bald obselet sein soll.

Viele Grüße

Lukas
Mitglied: Biber
Biber 09.11.2011 um 20:10:36 Uhr
Goto Top
Moin Overdue,

willkommen im Forum.


Zitat von @Overdue:
Das klappt bisher reibungslos! Vielen vielen Dank. Damit hast du mich schon ein gutes Stück weiter gebracht.
Dann gehört nach den Grundregeln dieses Forums ein absinthfarbenes Häkchen an den Beitrag.
Falls du so etwas nicht kennst: zur Not nimm ein waldmeisterfarbenes.


Nochmal zu meiner Frage: Was meinst du, auf welche Programmiersprachen ich mich für soclche Dinge konzentrieren sollte?
Ja nee, das merken wir hier, wenn du eine neue Frage stellst und das mit den Worten "Nochmal zu meiner Frage".
Wir sind vielleicht technisch und bezogen auf Rechtschreibung nicht auf dem neuesten Stand, aber die rhetorischen Bauernfänger-Formulierungen aus der Kohl-Ära erkennen wir schon noch.


..., jedoch habe ich gelesen, das VBScript bald obselet sein soll.

  • Definiere "gelesen". In der Computerbild? Im Kaffeesatz? Im Buch Salomons?
  • Definiere "bald". Sagt dir das Datum 21.12.2011 im Maya-Kalender irgendwas? "Bald" gibt es auch kein Windows XP mehr und kein Windows 7. Und in 300 Jahren gibt es auch keine gesperrte Zone um Fukushima.
  • Definiere "obsolet". Ist total out? Existiert nicht mehr? Wird nur noch von Sissis benutzt?

-> meine Empfehlung: wenn du ein Werkzeug wie VBScript nach einem Einarbeitungsaufwand von -ich sag mal- netto 10 Stunden halbwegs bedienen kannst, also quasi ab nächsten Freitag und dann 5 Jahre damit ausreichend klar kommst....

Was war noch mal die Frage?

Sonst nimm PowerShell .... ist zwar kryptisch, aber ist M$s momentaner Trendy-Tipp.

Grüße
Biber
Mitglied: bastla
bastla 09.11.2011, aktualisiert am 18.10.2012 um 18:49:04 Uhr
Goto Top
@Biber
Danke für's Aushelfen - die Antwort war eigentlich schon überfällig ... face-wink

@Overdue
Ich schließe mich Biber vollinhaltlich an face-wink - aber was das "Gar-nix-mehr-verstehen" angeht: Könntest Du das ev doch etwas einschränken und dann vielleicht eine konkrete Frage stellen?

Grüße
bastla

P.S.:
[Totally OT]
Zum Thema "überfällig": Mein 11111. Kommentar (ist vorhin ganz unspektakulär nebenan gelandet) wäre eigentlich schon vor 8 Tagen dran gewesen ... face-wink
[/Totally OT]
Mitglied: Overdue
Overdue 12.11.2011 um 06:36:59 Uhr
Goto Top
Hallo, ich habe den Beitrag jetzt mit dem grünen Häckchen als gelöst markiert, ich hatte dies nicht bedacht, entschuldigt bitte. Wie gesagt, bin neu hier.

@Biber

Das mit dem VBScript habe ich auf Wiki gelesen: http://de.wikipedia.org/wiki/VBScript#cite_note-0

Aber solche Fragen werde ich dann in einem neuen Thread starten.


@bastla

Das mit dem "Gar-nix-mehr-verstehen" war auf die Einbindung von VBScript bezogen, da ich mich damit überhaupt nicht auskenne.
Ich bin dir auch sehr dankbar, dass ich in Zunkunt auch konkrete Verständnisfragen stellen kann. Das werde ich auch tun, jedoch fehlt mir leider gerade die Zeit, mich intensiver damit auseinander zu setzen.

Vielen Dank nochmal für deine Hilfe!

Gruß

Lukas
Mitglied: Biber
Biber 12.11.2011 um 13:56:18 Uhr
Goto Top
[OT]
Moin Overdue,

danke für deine Antwort und deine Reaktion auf meinen Kommentar.

Eine Fussnote möchte ich noch anbringen zu der Neben-Frage, wie obsolet denn VBScript denn nun ist.

In dem von dir angeführten Wiki-Artikel wird zu diesem Aspekt auf einen Blog aus dem Jahr 2004 verwiesen.
Für mich ist beim Lesen allerdings die Essenz der damaligen Diskussion
  • VBScript ist "eingefroren" und wird nicht weiterentwickelt
  • dementsprechend kann wirklich niemand behaupten, VBScript wird als das strategisch M$-Produkt gehandelt
  • die hohe Akzeptanz allerdings wird eine langjährige Koexistenz mit Folgeprodukten bewirken.

Jetzt, 7 Jahre später, lässt sich nur hinzufügen: dass die nach meiner Wahrnehmung geringe Akzeptanz von WMIC, Powershell und ASP.NET wohl eher noch eine -wie Mutti Angie sagen würde - Restlaufzeitverlängerung bewirken wirkt.

Ich stehe jedenfalls zu meiner Behauptung oben, dass du mit VBScript noch schmerzfrei über die nächsten 5 Winter kommst.
Sofern es denn so viele für M$ gibt.

Grüße
Biber
[/OT]