Top-Themen

AppleEntwicklungHardwareInternetLinuxMicrosoftMultimediaNetzwerkeOff TopicSicherheitSonstige SystemeVirtualisierungWeiterbildungZusammenarbeit

Aktuelle Themen

Administrator.de FeedbackApache ServerAppleAssemblerAudioAusbildungAuslandBackupBasicBatch & ShellBenchmarksBibliotheken & ToolkitsBlogsCloud-DiensteClusterCMSCPU, RAM, MainboardsCSSC und C++DatenbankenDatenschutzDebianDigitiales FernsehenDNSDrucker und ScannerDSL, VDSLE-BooksE-BusinessE-MailEntwicklungErkennung und -AbwehrExchange ServerFestplatten, SSD, RaidFirewallFlatratesGoogle AndroidGrafikGrafikkarten & MonitoreGroupwareHardwareHosting & HousingHTMLHumor (lol)Hyper-VIconsIDE & EditorenInformationsdiensteInstallationInstant MessagingInternetInternet DomäneniOSISDN & AnaloganschlüsseiTunesJavaJavaScriptKiXtartKVMLAN, WAN, WirelessLinuxLinux DesktopLinux NetzwerkLinux ToolsLinux UserverwaltungLizenzierungMac OS XMicrosoftMicrosoft OfficeMikroTik RouterOSMonitoringMultimediaMultimedia & ZubehörNetzwerkeNetzwerkgrundlagenNetzwerkmanagementNetzwerkprotokolleNotebook & ZubehörNovell NetwareOff TopicOpenOffice, LibreOfficeOutlook & MailPapierkorbPascal und DelphiPeripheriegerätePerlPHPPythonRechtliche FragenRedHat, CentOS, FedoraRouter & RoutingSambaSAN, NAS, DASSchriftartenSchulung & TrainingSEOServerServer-HardwareSicherheitSicherheits-ToolsSicherheitsgrundlagenSolarisSonstige SystemeSoziale NetzwerkeSpeicherkartenStudentenjobs & PraktikumSuche ProjektpartnerSuseSwitche und HubsTipps & TricksTK-Netze & GeräteUbuntuUMTS, EDGE & GPRSUtilitiesVB for ApplicationsVerschlüsselung & ZertifikateVideo & StreamingViren und TrojanerVirtualisierungVisual StudioVmwareVoice over IPWebbrowserWebentwicklungWeiterbildungWindows 7Windows 8Windows 10Windows InstallationWindows MobileWindows NetzwerkWindows ServerWindows SystemdateienWindows ToolsWindows UpdateWindows UserverwaltungWindows VistaWindows XPXenserverXMLZusammenarbeit
GELÖST

Batch - Textzeile vor bestimmten Zeichen einfügen

Frage Entwicklung Batch & Shell

Mitglied: Okinami

Okinami (Level 1) - Jetzt verbinden

27.09.2008, aktualisiert 28.09.2008, 8534 Aufrufe, 8 Kommentare

Hallo Zusammen,

Ich würde gerne mit einem Bacth in einer *.ini Datei eine zusätzliche Textzeile einfügen.
Die Datei sieht etwa wie folgt aus:

[text]
text
text
text
text
[text]
text

Wie ist es möglich vor der zweiten [ eine neue Zeile mit einem Text einzufügen?

Würde mich freuen wenn mir jemand weiterhelfen kann.
Mitglied: bastla
27.09.2008 um 10:26 Uhr
Hallo Okinami und willkommen im Forum!

Soferne sich "[text]" und "[text]" unterscheiden, sollte es etwa so gehen:
01.
@echo off & setlocal 
02.
set "iniDatei=D:\Eine.ini" 
03.
set "Markierung=[text]" 
04.
set "Neu=neue Zeile mit einem Text" 
05.
 
06.
set "Bak=%temp%\Ini.bak" 
07.
move "%iniDatei%" %Bak% 
08.
for /f "tokens=1* delims=:" %%i in ('findstr /n "^" %Bak%') do (set "Zeile=%%j" & call :ProcessLine) 
09.
goto :eof 
10.
 
11.
:ProcessLine 
12.
if not defined Zeile (>>"%iniDatei%" echo\ & goto :eof) 
13.
if "%Zeile%" neq "%Markierung%" (>>"%iniDatei%" echo %Zeile% & goto :eof) 
14.
>>"%iniDatei%" echo %Neu% 
15.
>>"%iniDatei%" echo %Zeile% 
16.
goto :eof
Es wird eine Sicherungskopie der ini-Datei als "%temp%\Ini.bak" erstellt.

Grüße
bastla
Bitte warten ..
Mitglied: Okinami
27.09.2008 um 10:36 Uhr
Hallo bastla,

besten Dank für Deine Hilfe, denn das funktioniert schon fast perfekt. Aber was mache ich, wenn der Inhalt der zweiten [ ] klammer variert?
Was auf jedenfall bleibt ist die Tatsache, das der eingefügte Text vor der zweiten Klammer stehen soll.

[text]
text 1
text 2
text 3
text XYZ
[text]

text XYZ sollte der eingefügte Text sein. Jedoch kann man es auch nicht Zeilen abhänig machen, weil auch diese varieren.

Was wäre wenn ich das ganze mit findstr auswerte und nach der [ suche und dann die Zeile -1 einfüge?

Gruss Okinami
Bitte warten ..
Mitglied: bastla
27.09.2008 um 10:56 Uhr
Hallo Okinami!

Was wäre wenn ich das ganze mit findstr auswerte und nach der [ suche und dann die Zeile -1 einfüge?
Auch eine Möglichkeit - wenn allerdings das gesuchte Zeichen "[" ohnehin als erstes Zeichen in der Zeile steht, sollte es auch so gehen:
01.
@echo off & setlocal enabledelayedexpansion 
02.
set "iniDatei=D:\Eine.ini" 
03.
set "Markierung=[" 
04.
set "Neu=Das ist die neue Zeile" 
05.
set Pos=2 
06.
 
07.
set /a V=0 
08.
set "Bak=%temp%\Ini.bak" 
09.
move "%iniDatei%" %Bak% 
10.
for /f "tokens=1* delims=:" %%i in ('findstr /n "^" %Bak%') do (set "Zeile=%%j" & call :ProcessLine) 
11.
goto :eof 
12.
 
13.
:ProcessLine 
14.
if not defined Zeile (>>"%iniDatei%" echo\ & goto :eof) 
15.
if "%Zeile:~,1%"=="%Markierung%" ( 
16.
    set /a V+=1 
17.
    if !V! equ %Pos% >>"%iniDatei%" echo %Neu% 
18.
19.
>>"%iniDatei%" echo %Zeile% 
20.
goto :eof
Noch als kurze Erklärung zum Ablauf:

Wenn innerhalb einer Schleife oder, wie hier, einer If-Anweisung Variablenwerte (konkret: der Zähler %V% - siehe dazu unten) verändert werden, können diese geänderten Werte in dieser If-Anweisung nur dann sofort wieder ausgelesen werden, wenn "delayedExpansion" aktiviert ist - daher der Zusatz in der ersten Zeile.

Die Variable %Pos% gibt an, vor dem wievielten Vorkommen der Markierung die neue Zeile eingefügt werden soll.

Die "for"-Zeile dient dazu, alle Zeilen aus der ini-Datei auszulesen, wobei Leerzeilen verloren gehen würden, wenn nicht mithilfe der Nummerierungsfunktion von "findstr" jede Zeile im Format
01.
Zeilennummer:Zeileninhalt
gelesen würde.

Damit wirklich alle Zeilen erfasst werden, dient mit dem Zeichen "^" der Zeilenanfang als Suchkriterium - einen Anfang hat schließelich jede Zeile, ein Ende, im Sinne einer Zeilenschaltung, muss es aber bei der letzten Zeile einer Datei nicht unbedingt geben.
Da ja nur der Zeileninhalt interessiert, wird durch Angabe des Trennzeichens ("delimiters") ":" diese Zeile zerlegt, wobei "1*" dafür sorgt, dass nur die Teile "vor" sowie der "Rest ("*") nach" dem ersten Trennzeichen gebildet werden - diese stehen dann in den Schleifenvariablen %%i und %%j zur Verfügung.

Der Inhalt von %%j entspricht also der eigentlichen Zeile und wird daher einer entsprechenden Variablen zugewiesen, welche dann im Unterprogramm ":ProcessLine" weiter behandelt wird.

Hier wird zunächst überprüft, ob es sich um eine Leerzeile handelt. Ist dies der Fall, kann mit "echo\" eine Leerzeile in die Datei geschrieben und das Unterprogramm (mit "goto :eof") verlassen werden. Ein "echo %Zeile%" hätte den unerwünschten Effekt, dass, das ja dann der Befehl eigentlich nur "echo" lauten würde, die Statusmeldung "ECHO ist eingeschaltet (ON)." ausgegeben und damit in der Datei landen würde.
Die Sprungmarke ":eof" steht für "Ende" (des Batches - bei ihrer ersten Verwendung in Zeile 11 - oder eines Unterprogrammes, wie eben hier).

War die Zeile nicht leer, wird das erste Zeichen (zum Thema "Teilstrings" siehe "set /?") auf Übereinstimmung mit dem Suchbegriff (%Markierung%) geprüft.

Wird eine Übereinstimmung festgestellt, muss der Zähler %V% (für "Vorkommen") erhöht und danach mit der gewünschten Position verglichen werden. Bei diesem Vergleich wird mit der Schreibweise !V! die bereits angesprochene "delayedExpansion" erzwungen, wodurch der "hochgezählte" Wert richtig erkannt wird. Handelt es sich um die richtige Position, wird die neue Zeile in die Datei geschrieben.

Auf jeden Fall ist aber danach die soeben gelesene Zeile auch noch zu schreiben.

Grüße
bastla
Bitte warten ..
Mitglied: Okinami
28.09.2008 um 11:09 Uhr
Guten Morgen,

zuerst einmal herzlichen Dank für die ausführliche Erklärung. Nun glaube ich das ganze zu verstehen. ;O)
Jedoch habe ich trotzdem noch eine kleine Frage dazu:

Mit dem Batch mache ich ja zuerst eine Kopie der bestehenden Datei und füge dann Zeile für Zeile von der Kopie in die original Datei mit der zusätzlichen Zeile zurück.

Mit dem Befehl findstr /B /L /I C:[ /N C:\EINE.INI gelingt es, die Zeilennummer der Zeilen die ein "[" enthalten zu nummerieren und auszulesen.
Ist es nun nicht möglich zum Beispiel die Zahl in der zweiten Zeile weiterzuverwenden und dann eine zusätzliche Zeile bei der 2ten Zahl - 1 einzufügen?

Würde mich über eine Antwort freuen...

Gruss Okinami
Bitte warten ..
Mitglied: bastla
28.09.2008 um 11:21 Uhr
Hallo Okinami!

Die Zeilennummer zu kennen hilft nicht wirklich, da Du trotzdem die Zeilen per Schleife auslesen musst - eine Blockverarbeitung wäre nur in der Hinsicht möglich, dass Du eine bestimmte Anzahl von Zeilen am Anfang überspringen kannst (entweder mit "for" und "skip" oder mit "more +"), um so den Teil nach der einzufügeenden Zeile zu erhalten.

Für die Zeilen vor der Einfügeposition musst Du aber dennoch eine Schleife verwenden, welche zeilenweise einliest und die Zeilennummer vergleicht. Da außerdem ein Sprung aus der Schleife in Batch eigentlich nicht vorgesehen (und auch nicht empfohlen) ist, müssten auch die restlichen Zeilen noch durchlaufen werden - insoferne sehe ich keinen wirklichen Sinn in dieser Variante ...

... abgesehen davon: Hat die Datei genug Zeilen, so dass ein etwaiger Performancevorteil einer anderen Lösung überhaupt erkennbar wäre?

Grüße
bastla
Bitte warten ..
Mitglied: bastla
28.09.2008 um 12:20 Uhr
... aber da es Dir irgendwie ein Anliegen zu sein scheint:
01.
@echo off & setlocal 
02.
set "iniDatei=C:\Eine.ini" 
03.
set "Markierung=[" 
04.
set "Neu=Das ist die neue Zeile" 
05.
set Pos=2 
06.
set "Bak=%temp%\Ini.bak" 
07.
 
08.
set Z= 
09.
set /a Pos-=1 
10.
for /f "skip=%Pos% delims=:" %%i in ('findstr /B /C:"%Markierung%" /N "%iniDatei%"') do if not defined Z set Z=%%i 
11.
if not defined Z goto :eof 
12.
 
13.
set /a Z-=1 
14.
move "%iniDatei%" %Bak% 
15.
for /f "tokens=1* delims=:" %%i in ('findstr /n "^" %Bak%') do  if %%i leq %Z% >>"%iniDatei%" echo\%%j 
16.
>>"%iniDatei%" echo %Neu% 
17.
>>"%iniDatei%" more +%Z% %Bak%
In Zeile 9 wird (durch Überspringen der ersten [= %Pos%-1] Ergebniszeile) die Zeile mit dem zweiten Vorkommen des Suchbegriffes ermittelt.

Soferne sie gefunden wurde (falls nicht, wird der Batch einfach beeendet), können alle Zeilen, die davor liegen (daher bis inklusive %Z%-1), in die neue Datei geschrieben werden.

Danach wird die neue Zeile angefügt und schließlich der Rest (durch Überspringen der Zeilen bis Zeilennummer %Z%-1 [da diese Berechnung schon vorher erfolgt ist, kann unmittelbar die Variable %Z% verwendet werden]) in die neue Datei geschrieben.

Grüße
bastla

[Edit] Berücksichtigung der Variablen %Pos% ergänzt. [/Edit]
Bitte warten ..
Mitglied: Okinami
28.09.2008 um 13:00 Uhr
Hallo nochmals,

mittlerweilen existieren bereits zwei Lösung die einwandfrei funktionieren.
Jedoch habe ich noch eine letzte Frage:

Ich möchte verhindern das der Batch zweilmal ausgeführt werden kann. Das mache ich mit dem Befehl

type %iniDatei% | find /I %Neu%
if errorlevel 1 goto start
if errorlevel 0 goto end

:start
Echo Eintag wird erstellt
ping -n 8 localhost>NUL

Diese Zeilen füge ich am Anfang des Batchs ein, also vor der Zeile 01.
Danach folgt einer der beiden "bastla"-Batch ;O)

Am Ende füge ich noch folgendes an:

:end
Echo Eintrag existiert bereits
ping -n 8 localhost>NUL

Man glaubt es kaum, es funktioniert sogar!!

Nun möchte ich am Ende der Schleife weiter Befehle ausführen, zum Beispiel noch eine weiter Zeile am Ende der ini Datei einfügen.
Aber wo setze ich den Befehl, so das er nicht bei jedem Schlaufendurchgang wiederholt wird?

Gruss Okinami
Bitte warten ..
Mitglied: bastla
28.09.2008 um 13:52 Uhr
Hallo Okinami!

Ich möchte verhindern das der Batch zweilmal ausgeführt werden kann.
Die Überprüfung ließe sich etwas knapper so formulieren:
01.
findstr /c:"%Neu%" "%IniDatei%">nul && goto :end
Nach dieser Zeile kann dann bereits der ":start"-Teil folgen, was einen Sprung dorthin überflüssig macht.

Nun möchte ich am Ende der Schleife weiter Befehle ausführen, zum Beispiel noch eine weiter Zeile am Ende der ini Datei einfügen.
Aber wo setze ich den Befehl, so das er nicht bei jedem Schlaufendurchgang wiederholt wird?
Das Ende des Hauptprogrammes ist im ersten Fall die Zeile 11 ("goto :eof") - daher können alle unmittelbar vor dem Ende (aber nach der Schleife) durchzuführenden Befehle dort eingefügt werden.

Bei der zweiten Version ist es noch einfacher - hier muss ohnehin nach der Schleife noch in die Datei geschrieben werden (und es wird auch, anders als oben, kein Unterprogramm verwendet), sodass weitere Zeilen am Ende des Batches angefügt werden können.

Grüße
bastla
Bitte warten ..
Neuester Wissensbeitrag
Windows 10

Powershell 5 BSOD

(5)

Tipp von agowa338 zum Thema Windows 10 ...

Heiß diskutierte Inhalte
LAN, WAN, Wireless
gelöst Server erkennt Client nicht wenn er ausserhalb des DHCP Pools liegt (28)

Frage von Mar-west zum Thema LAN, WAN, Wireless ...

Windows Server
Server 2008R2 startet nicht mehr (Bad Patch 0xa) (18)

Frage von Haures zum Thema Windows Server ...

Outlook & Mail
Outlook 2010 findet ost datei nicht (18)

Frage von Floh21 zum Thema Outlook & Mail ...

Netzwerkmanagement
gelöst Anregungen, kleiner Betrieb, IT-Umgebung (17)

Frage von Unwichtig zum Thema Netzwerkmanagement ...