mathe172
Goto Top

Komplette Ausgabe einer For -f Schleife in die gleiche Datei zurück

Hallo zusammen!

Dank diesem hilfreichen Tipp sind meine Versuche, kurze und effiziente Batches zu schreiben, meiner Meinung nach noch erfolgreicher geworden face-smile
Nun wurde in letzter Zeit mehrmals nach einem Skript gefragt, das eine Datei Zeilenweise verarbeitet und die Zeile bei Bedarf verändert. Das ganze soll wieder in der Ausgangsdatei landen...

Nun war mein Ansatz vereinfacht so:
@echo off
::Gesamte Ausgabe der Schleife umleiten
(for /f "usebackq delims=" %%A in ("Datei.txt") do echo.%%A)>"Datei.txt"  
Dieser Code sollte ja eigentlich jede Zeile von "Datei.txt" ausgeben und das alles wieder in die Datei schreiben.
Nun kommt aber die Fehlermeldung: Datei wurde nicht gefunden. -Seltsamerweise ist die Datei aber trotzdem leer, als ob die For-Schleife die Datei nicht findet, die Umleitung aber schon.

Da ich bis jetzt immer zu einer Temporären Datei gezwungen war, wollte ich wissen ob es an mir, der cmd.exe, der Programmunlogik oder am (wahrscheinlich) bekifften Programmierer liegt.
Vielleicht steht die Erklärung ja schon in dem oben genannten Beitrag und ich finde sie nicht.

Ich hoffe ihr wisst mehr face-smile
MfG,
Mathe172

Content-Key: 162713

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

Printed on: April 25, 2024 at 23:04 o'clock

Member: Highend01
Highend01 Mar 15, 2011 at 20:42:38 (UTC)
Goto Top
Die Umleitung braucht die Datei nicht zu "finden", es legt sie schlicht und ergreifend an / überschreibt sie bei jedem Scriptdurchlauf.

Wie hattest du es dir bitte vorgestellt, zeilenweise Daten aus einer Datei auszulesen, die schon vor der Ausgabe der ersten Zeile wieder überschrieben wird (und damit 0 Inhalt hat)??
Member: bastla
bastla Mar 15, 2011, updated at Oct 18, 2012 at 16:46:11 (UTC)
Goto Top
@Highend01
Der Plan wäre es ja, zunächst (in der Klammer) alle Zeilen auszulesen und auszugeben, und erst danach die Ausgangsdatei mit dem "Gesamtergebnis" zu überschreiben (der Link Schleife ohne mehrmaliges Öffnen der Datei in welche Umgeleiteitet wird ist oben bei "diesem" leicht zu übersehen) ...

@mathe172
Wäre tatsächlich eleganter als das klassische
move "Datei.txt" %temp%\Datei.txt  
for /f "delims=" %%A in (%temp%\Datei.txt) do >>"Datei.txt" echo %%A  
del %temp%\Datei.txt
oder (leerzeilenbewahrend)
move "Datei.txt" %temp%\Datei.txt  
for /f "tokens=1* delims=:" %%A in ('findstr /n "^" %temp%\Datei.txt') do >>"Datei.txt" echo.%%B  
del %temp%\Datei.txt
bzw
move "Datei.txt" %temp%\Datei.txt  
(for /f "tokens=1* delims=:" %%A in ('findstr /n "^" %temp%\Datei.txt') do echo.%%B)>"Datei.txt"  
del %temp%\Datei.txt
Grüße
bastla

[Edit] Fehlerhafte Schreibweise von "%temp%\Datei.txt" korrigiert [/Edit]
Member: Highend01
Highend01 Mar 15, 2011 at 21:03:39 (UTC)
Goto Top
@bastla

"und erst danach" beschreibt ja schon den eigentlichen Ansatz, das Ganze über eine temporäre Datei zu lösen. Dies wurde hier "vergessen" und deshalb funktioniert seine Herangehensweise ja auch nicht. Völlig unabhängig davon, ob er jetzt die Zieldatei immer neu geöffnet + geschrieben hätte (per >>) oder in einem Rutsch übertragen wollte face-smile

Du hast übrigens einen kleinen Schreibfehler in deinem Beispiel drin (nicht, dass es übernommen wird und dann die Frage gestellt wird, warum es nicht läuft):

('findstr /n "^" %temp%\Datei.txt')  
Member: mathe172
mathe172 Mar 15, 2011 at 21:08:09 (UTC)
Goto Top
Hallo zusammen,
Erst mal danke für die Antworten!
Dies wurde hier "vergessen" und deshalb funktioniert seine Herangehensweise ja auch nicht.
Kannst du das bitte erklären? Wieso funktioniert jetzt die extrem-Kruzform nicht?

Mathe172
Member: bastla
bastla Mar 15, 2011 at 21:09:17 (UTC)
Goto Top
@Highend01
Danke für's genaue Hinsehen face-smile - ich korrigier's oben ...
Vielleicht schaust Du Dir aber trotzdem den verlinkten Tipp von PH an, um zu erkennen, was die Grundidee von mathes Ansatz war ...

Grüße
bastla
Member: Highend01
Highend01 Mar 15, 2011 at 21:12:54 (UTC)
Goto Top
Zitat von @bastla:
Vielleicht schaust Du Dir aber trotzdem den verlinkten Tipp von PH an, um zu erkennen, was die Grundidee von mathes Ansatz war

Hatte ich getan. Deshalb hatte ich ja noch mal drauf geantwortet.

@mathe172

Weil deine Ein- und Ausgabedatei übereinstimmen. Verwende eine temporäre Datei für das Auslesen / alt. Schreiben.
Member: jeb-the-batcher
jeb-the-batcher Mar 15, 2011 at 21:20:48 (UTC)
Goto Top
Hallo,

so einfach ist es dann auch wieder nicht.

Genau genommen würde das Konstrukt von mathe0815 dazu führen, dass die Datei neu erzeugt wird, dann aber Zeile für Zeile die Daten angehängt werden.

Aber wie schon erkannt klappt das nicht.

Erstaunlicherweise scheint es an sich auch egal zu sein, dass sich der Inhalt der Datei ändert, die Datei scheint gecached zu werden!
Sprich, es können Daten gelesen werden die gar nicht mehr da sind.

Test mit
@echo off
( for /l %%n in (1,1,3) do echo %%n) > t.txt

rem for %%a in (1) DO (
for /F "delims=" %%b in (t.txt) DO 	(  
	echo fileOut=%%b
	>con echo aktuelle Zeile "%%b"  
	>con echo - Kompletter Inhalt von t.txt ----
	>con type t.txt
	>con echo - Datei ende ----
	>con echo(
) > t.txt

--- OUTPUT ----

aktuelle Zeile "1"  
- Kompletter Inhalt von t.txt ----
fileOut=1
- Datei ende ----

aktuelle Zeile "2"  
- Kompletter Inhalt von t.txt ----
fileOut=2
- Datei ende ----

aktuelle Zeile "3"  
- Kompletter Inhalt von t.txt ----
fileOut=3
- Datei ende ----

Nur leider klappt es eben nicht mehr, wenn man die ganze For-Schleife in einen Block packt.

Gruß
jeb
Member: Biber
Biber Mar 15, 2011 at 21:50:19 (UTC)
Goto Top
Moin,

ich weiss zwar nicht genau, was denn das erhoffte Einsparpotential sein soll, andererseits .... wird ja bestimmt für einen guten Zweck sein.
Und ist bestimmt besser, als irgendwo rumzuhängen...

Wieso findet ihr das Verhalten denn absonderlich?
Wenn eine Umleitung mit einer Pipe (also hier dem ">"-Zeichen) verlangt wird, dann wird zuerst das Ziel als Filehandle geöffnet,
und dabei eine 0-Byte-Datei im Verzeichnis angelegt, bevor überhaupt irgendeine Ausgabe zu schreiben ist.

Einfacher zum Nachvollziehen:
  • Macht einfach zwei CMD-Fenster auf, lasst beide im Standardverzeichnis stehen
  • ruft in einem die Sleep.exe auf mit einem für Langsamtipper angemessenen Wert, z.B 20 oder 200 [sec] und leitet das Ergebnis um
sleep 20>sleeptest.txt

Im anderen Fenster macht ihr ein
dir sleept*.*
...
15.03.2011  22:41                 0 sleeptest.txt

...die Datei ist da, LANGE bevor da irgendein Output kommen könnte... die SLEEP.exe ist immer noch am Rumwarten.

Und dieses "Umleitungsziel wird zuerst angelegt"-Verhalten erklärt doch die Mathe-Frage zur Genüge, oder?

Wie sollte es denn auch anders sein?
Eine andere "Reihenfolge" wäre doch fatal.
Angenommen, eine 10-Gigabyte-Datei sollte per "type monsterlog.txt" umgeleitet werden auf "eineReadonlyDatei.txt".
Soll zuerst der "Type monsterlog.txt" vollständig durchrödeln, auch wenn er den Output im Ziel nicht schreiben kann?

Oder auch hier ein einfaches Beispiel:
[Das führende ">" gehört zum CMD-Prompt - nicht mit Eintippseln]
>echo x >readonly.txt

(=22:57:03  D:\temp=)
>attrib readonly.txt +r

(=22:57:07  D:\temp=)
>dir c:\  /s /b >readonly.txt
Zugriff verweigert
und er führt NICHT zuerst den kompletten DIR-Liste-mir-2-Millionen-Dateien-auf aus, sondern öffnet erst das Ziel "readonly.txt" oder verreckt.

Grüße
Biber
Member: bastla
bastla Mar 15, 2011 at 21:58:52 (UTC)
Goto Top
[OT]
@Biber
ich weiss zwar nicht genau, was denn das erhoffte Einsparpotential sein soll
... hybsch wär's gewesen face-wink (und da ja die 10-Gigabyte-Text-Dateien doch noch nicht soo überhandnehmen dürften, könnten sich die die paar GB RAM auch einmal nützlich machen) ...

Grüße
bastla
[/OT]
Member: Biber
Biber Mar 15, 2011 at 22:13:46 (UTC)
Goto Top
[noch OTiger]
@bastla

Wenn meine geheimsten Hoffnungen in Erfüllung gehen...
und Karl Theodor zu Guttenberg tatsächlich Goldbärchens Nachfolger wird und "Wetten dass.." moderiert....

-> dann werde ich ihm ein paar Kandidaten nennen, die mit einer Querflöte 10 Schokopuddings in einer Minute durch einen Heuballen blasen können.
Oder zumindest ähnliches vorturnen . face-wink

Grüße zurück
Biber
[/noch OTiger]
Member: pieh-ejdsch
pieh-ejdsch Mar 15, 2011 at 22:27:12 (UTC)
Goto Top
moin,

Wenn eine Umleitung mit einer Pipe (also hier dem ">"-Zeichen) verlangt wird, dann wird zuerst das Ziel als Filehandle geöffnet,
genau das wollte ich auch gerade schreiben

normal kommt ja auch ein Fehler, wenn eine bestimmte Datei nicht existiert, aber wenn die Zeile eingelesen wird und eine Datei lesegeschützt zum Schreiben geöffnet wird - wird diese in diesem Moment auch erstellt und ist auch vorhanden bei der ausführung der Batch-/CMDZeile.
aber als kleinen test im CMD:
if exist "%temp%\testdatei.txt" del "%temp%test\datei.txt"
type "%temp%\testdatei.txt"

type "%temp%\testdatei.txt">"%temp%\tesdatei.txt"
type "%temp%\testdatei.txt"

wegen der einzelumleitung des kompletten Befehles ist es ja so, das zu Beispiel:
type nul>D:\testdatei.txt
(for /l %i in (1,1,100000) do @echo.)>D:\testdatei.txt
bei mir ~ 5 sekunden dauerte, aber
type nul>D:\testdatei.txt
for /l %i in (1,1,100000) do @echo.>>D:\testdatei.txt
~ 1 min 45 sek dauerte

Zeitmessung über Batchdatei
das kann ich mir nur erklären das beim 1. mal die Datei nur 1 mal geöffnet und abschliesend geschlossen wird -> schprich ein Schreibzugriff
beim zweiten mal hingegen wird die Datei 100.000 mal geöffnet und auch genausoviel mal wieder geschlossen - abgesehne von den Lese-/Schreibzugriffen in der MFT

was allerdings die Forschleife von Jeb macht kann ich nicht erklären.

Gruß Phil
Member: mathe172
mathe172 Mar 16, 2011 at 12:33:25 (UTC)
Goto Top
Hallo zusammen,
ich danke euch für die vielen Antworten!
Ich mach mal den Haken hin, da die Anfangsfrage ja gelöst wurde.

Vielleicht lässt sich Jeb's Schleife ja so erklären:
ForSchleife:Datei einlesen und zwischenspeichern
Klammer nach do: Ganze Klammer wird umgeleitet, also t.txt neu erstellen
echo-Befehl: Nichts anderes Angegeben, also nach t.txt
type-Befehl:Datei einlesen und ausgeben
Nächster Durchgang (ab Klammer nach Do)

Dagegen war mein Versuch:
Klammer vor For: Ganze Klammer wird umgeleitet, also Datei.txt neu erstellen
ForSchleife:Datei einlesen und zwischenspeichern-->Findet nichts, keine Schleifendurchgänge
-->nicht steht mehr in der Datei

Danke nochmal,
Mathe172