django.durano
Goto Top

Bestimmten Bereich einer Textdatei ausgeben mittels Batch

Hallo,

gibt es eine Möglichkeit eine Textdatei mittels Batch zu durchsuchen und einen bestimmten Teil davon dann aber nur auszugeben?

Folgendes Beispiel:

Meine Textdatei sieht wie folgt aus:

Episode
1
2
3
4
5
6

Beschreibung
Hier steht eine Beschreibung

usw.

Besteht hier nun die Möglichkeit nach Episode zu suchen und dann alles was nach Episode folgt bis Beschreibung auszugeben und bei Beschreibung zu stoppen?
Das was zwischen Episode steht also 1,2,3 usw. variert, ist also nicht immer eine bestimmte Anzahl.

Ich kenne mich etwas mit Batchrex aus und wie ich eine normale Textdatei durchsuche und dann eben das auszugeben was dort drin steht, allerdings weis ich nicht ob es möglich ist nur einen bestimmten Bereich zu durchsuchen.

Ich denke hier muss man mit Regular Expressions arbeiten, damit kenne ich mich aber leider nicht wirklich aus.

Hoffe konnte vermittlen was ich gerne hätte.

Gruß Django

Content-Key: 347848

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

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

Member: rubberman
Solution rubberman Aug 31, 2017 at 18:34:01 (UTC)
Goto Top
Der Regex Support von Batch beschränkt sich auf das bisschen, was FINDSTR versteht (wenn man nicht auf andere Sprachen oder Drittprogramme zurückgreifen will).

Gehen wir von folgenden Voraussetzungen aus:
- Die Textdatei ist in einer Single Byte Codepage codiert.
- Die Suchbegriffe bilden eine separate Zeile (ohne voran- oder nachgestellte Leer- oder sonstige Zeichen).
- Die maximale Länge einer Zeile überschreitet nicht 1021 Zeichen.

@echo off &setlocal
set "infile=test.txt"  

for /f "delims=:" %%i in ('findstr /nx "Episode" "%infile%"') do set "begin=%%i"  
for /f "delims=:" %%i in ('findstr /nx "Beschreibung" "%infile%"') do set /a "end= %%i - begin - 1"  

setlocal EnableDelayedExpansion
<"!infile!" (  
  for /l %%i in (1 1 %begin%) do set /p "="  
  for /l %%i in (1 1 %end%) do (
    set "line=" &set /p "line="  
    echo(!line!
  )
)
pause

Grüße
rubberman
Member: Django.Durano
Django.Durano Sep 02, 2017 at 15:17:28 (UTC)
Goto Top
Danke für deine schnelle Antwort.
Der Code erfüllt genau was ich mir vorgestellt habe.

Nur kurz zum Verständnis.

for /f "delims=:" %%i in ('findstr /nx "Episode" "%infile%"') do set "begin=%%i"  
for /f "delims=:" %%i in ('findstr /nx "Beschreibung" "%infile%"') do set /a "end= %%i - begin - 1"  

Die beiden For-Schleifen sind quasi dafür gedacht um den Bereich abzustecken zwischen Epsiode und Beschreibung sehe ich das richtig?
Der Command /nx steht hier gleichnamig für /n /x oder?

setlocal EnableDelayedExpansion
<"!infile!" (  
  for /l %%i in (1 1 %begin%) do set /p "="  
  for /l %%i in (1 1 %end%) do (
    set "line=" &set /p "line="  
    echo(!line!
  )
)

In dem Block hier wird quasi anhand des oben abgesteckten Bereiches Zeilenweise durchgezählt und das gefundene dann ausgegeben?`

Soweit richtig?


Gruß Django
Member: rubberman
rubberman Sep 02, 2017 at 16:07:56 (UTC)
Goto Top
Ja, /nx ist hier kurz für /n /x. Das /n führt dazu, dass FINDSTR der gefundenen Zeile die Zeilennummer und ein Doppelpunkt voranstellt (und die Zeilennummer ist das, was wir jeweils brauchen). Das /x bedeutet, dass die gesamte Zeile dem Suchpattern entsprechen muss. Anderenfalls würden auch Zeilen gefunden, die das Suchpattern nur an irgendeiner Stelle beinhalten.

Das <"!infile!" (leitet den Filestream an den kompletten Klammernblock um, sodass mit SET /P jeweils eine Zeile gelesen wird.
Die erste FOR /L Schleife liest also alle Zeilen bis zum Beginn des gesuchten Blocks. Der Zeileninhalt wird aber keiner Variablen zugewiesen (also wird er de facto verworfen).
Die zweite FOR /L Schleife liest die vorher mit SET /A berechnete Anzahl an Zeilen jeweils in Variable lineein und gibt sie mit ECHO aus.

Grüße
rubberman
Mitglied: 77559
77559 Sep 03, 2017 at 11:57:30 (UTC)
Goto Top
Unter den gleichen Prämissen wie bei rubberman ist diese Batchdatei etwas simpler:

@echo off &setlocal
set "InFile=test.txt"  
set "Von=Episode"  
set "Bis=Beschreibung"  
set "Flag="  
For /f "tokens=1* delims=]" %%A in ('find /V /N "§+#*$" ^<%InFile%') DO (  
    if "%%B"=="%Bis%"  Set "Flag="  
    If defined Flag echo:%%B
    if "%%B"=="%Von%" Set "Flag=1"  
)

Mit PowerShell tut's ein (wenn auch komplexer) Einzeiler, nutzbar von der cmdline oder auch in einer Batchdatei:
powershell -NoP -C "gc test.txt -raw |sls '(?sm)(?<=^Episode\r?\n).*(?=\r?\nBeschreibung)'|%{$_.Matches.value}"  

Dasselbe als PowerShell Script ohne Aliase:
Get-Content test.txt -Raw | 
  Select-String '(?sm)(?<=^Episode\r?\n).*(?=\r?\nBeschreibung)'|  
    ForEach-Object {
      $_.Matches.value
    }

Kern ist ein Regulärer Ausdruck (RegEX) mit Lookarounds

Gruß LotPings
Member: rubberman
rubberman Sep 03, 2017 at 17:58:24 (UTC)
Goto Top
Zitat von @77559:
... ('find /V /N "§+#*$" ^<%InFile%') ...

Nanu face-surprise ... ('find /V /N "" ^<"%InFile%"') ... oder haben die Zeichen irgendeine Bewandtnis, die ich nicht verstehe?

Grüße
rubberman
Member: Django.Durano
Django.Durano Sep 05, 2017 updated at 09:18:08 (UTC)
Goto Top
@77559
Erstmal danke für deine Antwort.


@echo off &setlocal
set "InFile=test.txt"  
set "Von=Episode"  
set "Bis=Beschreibung"  
set "Flag="  
For /f "tokens=1* delims=]" %%A in ('find /V /N "§+#*$" ^<%InFile%') DO (  
    if "%%B"=="%Bis%"  Set "Flag="  
    If defined Flag echo:%%B
    if "%%B"=="%Von%" Set "Flag=1"  
)

Ehrlich gesagt verstehe ich deine Batch viel weniger als die von Rubberman. Außerdem fehlt hier nicht auch die Definition von %%B?
%%A wird ja durch die For-Schleife deklariert aber %%B fehlt mir irgendwie.
Würde ja dann heißen wenn
leer==Beschreibung set flag=
Oder habe ich etwas übersehen?


@rubberman

Danke für die Erklärung. Das umleiten des Filestreams ist mir aber noch nicht ganz klar bzw. wie ich das genau anwenden kann.
Ich kannte bisher nur das ich den Filestream in eine Textdatei umleiten kann mit > bzw. >>
Ist das hier quasi so eine Art Umkehrung, das die Textdatei eingelesen und hierdurch dann übergeben wird an das nachfolgende?
Member: rubberman
rubberman Sep 05, 2017 at 10:10:06 (UTC)
Goto Top
Zitat von @Django.Durano:
Ich kannte bisher nur das ich den Filestream in eine Textdatei umleiten kann mit > bzw. >>
Ist das hier quasi so eine Art Umkehrung, das die Textdatei eingelesen und hierdurch dann übergeben wird an das nachfolgende?
Fast. >und >>leiten das stdout an einen Filestream um, während <einen Filestream an das stdin umleitet. Insgesamt gibt es 3 Standarddatenströme. Der 3. ist das stderr. Hast vielleich schon gemerkt, dass du 2>oder 2>>schreiben musst, um Fehlermeldungen umzuleiten.

Grüße
rubberman
Mitglied: 77559
77559 Sep 05, 2017 at 19:50:59 (UTC)
Goto Top
@rubberman
  • Der String "§+#*$" in Verbindung mit /V als unwahrscheinlich vorkommender Teil (soll alles durchlassen, es geht um die Numerierung)
> find /V /N "$$$" <test.txt  
[1]Episode
[2]1
[3]2
[4]3
[5]4
[6]5
[7]6
[8]
[9]Beschreibung
[10]Hier steht eine Beschreibung
[11]
[12]usw.
@django
  • Ich finde eine Schleife einfacher als vier - aber ein paar Erklärungen mehr hätten nicht geschadet.
  • find statt findstr wegen der eckigen Klammer als Abgrenzung ( die schließende Klammer dürfte seltener als erstes Zeichen einer Zeile auftreten als ein Doppelpunkt)
  • Die Umleitung damit find nicht den Dateinamen mit ausgibt.
  • Das Flag statt eines Variableninhalts der EnableDelayedExpansion erfordern würde (if defined funktioniert auch ohne)
  • Flag funktioniert als Schalter wann ausgegeben werde soll
  • mit tokens wird festgelegt wieviele Variablen genutzt werden 1=%%A, *=%%B (Rest der Zeile) %%A enthält nur die verworfene Numerierung in eckigen Klammern [1] etc.
Member: rubberman
rubberman Sep 05, 2017 at 21:39:40 (UTC)
Goto Top
Zitat von @77559:

@rubberman
  • Der String "§+#*$" in Verbindung mit /V als unwahrscheinlich vorkommender Teil (soll alles durchlassen, es geht um die Numerierung)
Joa und der leere String "" in Verbindung mit /V findet alle Zeilen die nicht nichts enthalten und auch nicht keinen Zeilenumbruch haben, also alle Zeilen incl. Leerzeilen face-wink
Ansonsten war mir klar, wie es funktioniert. (Die Erklärung wird aber für Django.Durano sicher nützlich sein.)

Grüße
rubberman
Member: Django.Durano
Django.Durano Sep 09, 2017 at 12:40:47 (UTC)
Goto Top
Erstmal danke für eure Hilfe.

Ich schau mir den Code von Lotpings nochmal an.
Wenn ich noch Fragen habe melde ich mich einfach wieder.