Batch Schleife in Schleife, was mache ich falsch?

Das Ergebnis basiert auf 2 Abstimmungen

Oh Gott, Oh Gott was machst du da. Mach das ganz anders! 100%
Der Weg zur Lösung ist gut. 0%
Mir fällt ein Besserer ein. Dieser wäre: 0%

3 Antworten

Vom Fragesteller als hilfreich ausgezeichnet

weshalb Du da auch noch Abstimmen lässt ist mir nicht einleuchtend...

Ansonsten typischer Anfängerkram... und der Ausführungsblock (do) wird nicht abgeschlossen die Batch stürzt ab... das wars erstmal.

Weshalb Du etwas umbenennst ist mir unklar? Reißt Du auch die Wand ab wenn du wissen möchtest was drausen los ist😅? nee.. Du schaust aus dem Fenster ohne was zu verändern...

Meine Vorstellung wie es ordentlich laufen sollte:

@echo off
chcp 65001 >nul
  rem aktuellen ordner sichern
pushd "%cd%"
  rem basisordner für die recursive Suche für aktuellen Ordner leer lassen (ich suche zur Demo mal unter windows\inf, da sind  garantiert Treffer )
set "baseFolder=%windir%\inf\"
  rem suche alle Dateien, welche irgendwie oem enthalten und mit .inf enden, unterhalb dem Basisordners..
for /f "delims=" %%a in ('dir "%basefolder%*oem*.inf" /a-d /b /s ') do (
      rem mal anzeigen was wir gefunden haben
    echo gefunden : "%%~nxa"
    echo im Ordner: "%%~dpa"
    set "fileFolder="%%~dpa"
)
echo das letzte Verzeichnis war: "%fileFolder%" 


pause

...es gibt noch zig andere Wege.

Dreh- und Angelpunkt ist immer das wissen was eine Schleife tut. Zum Testen mal @echo off am Anfang zu entfernen und innerhalb der schleifen mit echo zu schauen was aktuell in einer Variable steckt hilft gegen Fragen wie:

jedoch bleibt die Variable "drv" leer...

die Schleife selbst ist soweit ok, vielleicht ist nur nix reingegeben worden?

dein Ansatz geht auch wenn es "mit der Kirche ums Dorf kutschen" ist:

@echo off
chcp 65001 >nul
pushd "%cd%"
set "baseFolder=%windir%\inf\"
for /f "delims=" %%a in ('dir "%basefolder%*oem*.inf" /a-d /b /s ') do (
    echo gefunden : "%%~nxa"
    echo im Ordner: "%%~dpa"
    cd "%%~dpa"
      rem und das nun aktuelle Verzeichnis in die Variable geben (geht doch)
    for /f "delims=" %%f in ('cd') do (
        echo  echo ordner über CD- Kommando: "%%~f"
        set "myFolder=%%~f"
    )
    echo:
)
echo das letzte übergeordnete Verzeichnis war: "%myFolder%" 
popd
cd
pause

Die Aussage von @daCypher ist nicht von der Hand zu weisen.

aber auch in Batch ist es ohne allen Schnickschnack eine Zeile:

for /f "delims=" %%a in ('dir "*oem*.inf" /a-d /b /s ') do (set "myFolder=%%~dpa")
Woher ich das weiß:eigene Erfahrung – Ich mach das seit 30 Jahren
Oh Gott, Oh Gott was machst du da. Mach das ganz anders!

Was genau willst du machen? Dir ist schon klar, dass du den Pfad, an dem eine Datei liegt, ganz einfach erhalten kannst, oder?

https://docs.microsoft.com/en-us/windows-server/administration/windows-commands/call#batch-parameters

Jan0000 
Fragesteller
 07.10.2021, 12:19

Ok danke. Ich brauche dann wahrscheinlich %~p1

An der Umsetzung scheitere ich jedoch noch.

Wie würde das aussehen wenn ich es innerhalb der Schleife auf %%a anwenden möchte?

1
Destranix  07.10.2021, 13:10
@Jan0000

Irgendwie einen Haufen Prozente vorne dranklatsche. Ich kenne mich mit Batch nur am Rande aus, Variablen sind da etwas komisch.

0
Jan0000 
Fragesteller
 07.10.2021, 14:54
@Erzesel

Ich glaube ich bin zu doof.

Habe folgendes probiert:

Echo %%~dpa %%a

Aber es funktioniert nicht...

0
Destranix  07.10.2021, 14:59
@Jan0000

Wie sieht der ganze Code aus? und was bekommst du als Ausgabe?

0
Erzesel  07.10.2021, 15:16
@Destranix

Die Variablen von Batch sind nicht anders als in anderen Sprachen.

Da Batch in den 80en geschaffen wurde um ganz primitive Aufgaben zu übernehmen wurde es auch nicht für nötig erachtet Strings generell in "Gänsefüßchen" zu setzen. Ergo kennzeichnete man zu lesende Variablen durch einfassen mit %-zeichen: %Variable%

Für Schleifenvariablen setzte man 2 %-Zeichen vor einen Buchstaben %%a mehr ist da nicht an Basiswissen nötig.

Es gibt noch wesentlich komplexere Konstrukte, wenn man mit (Pseudo)Arrays und Strukturen arbeitet, aber das dürfte eine Batchschreiber welcher lediglich in Paar kleine Dinge automatisch erledigen möchte nicht berühren. Ich habe diesbezüglich schon wahre %%-Orgien veranstaltet. ...letztlich ein Frage der Übung.

Bezüglich der Laufvariablen gibt es bei direkter Eingabe in die Konsole eine Ausnahme: dies haben dann nur ein % vor dem Buchstaben. (daran ist ja nun nichts schwer)

Aber auch moderne Sprachen wie Powershell kennzeichnen Variablen als solche $Variable , damit ist die Variable von anderen Schlüsselworten zu unterscheiden....

1
Destranix  07.10.2021, 15:27
@Erzesel

Das ist nicht die einzige Sache, die mich stört. Im Grudne muss ich meist haufenweise Zeug googeln, wenn ich Batch-Code schreibe und dabei Sachen, die eigentlich selbstverständlich sein sollten.

Echt nervig vor allem, wenn irgendwie je nach Kontext mal ein anderes Zeichen zum escapen da ist und ich auch sonst irgendwie je nach Kontext alles anders schreiben muss, damit das funktioniert.

Mal ein Beispiel:

FORFILES /m *.png /c ^"cmd /v:ON /c ^
    set "tmp_path=@path" ^& echo file !tmp_path:\^"='! >> %uniqueFileName% ^& echo duration 1 >> %uniqueFileName% ^
^"

Hättest du auf Anhieb dabei gewusst, was du wie escapen musst? Komisch ja, dass ich die Äußeren Anführungszeichen escapen muss, die inneren nicht und einfache auch nicht, aber zweifache. Und dass das Ampersand escapt werden muss, aber andere Operatoren nicht.
(Ist jetzt nur ein zufällig rausgepicktes Beispiel)

Variable hier übrigens mit '@' gekennzeichnet nicht mit '%', was zusätzlich verwirrend ist.

0
Erzesel  07.10.2021, 16:28
@Jan0000

vielleicht gibt es in dem Ordner, welchen Du mit dir durchsuchst, nichts mit dem gewünschten dateimuster? darum habe ich ja auch oben zu Demo den windowsOrdener als Basisordner eingefügt, weil dort garantiert oem*.inf gefunden werden!

wenn dir "*oem*.inf" /a-d /b /s außerhalb der schleife kein Ergebnis liefert , wird es dies auch nicht im Schleifenkopf tun.

versuche erstmal ein wenig den Umgang mit dir .

dir /ad /s /b "*.*" alle Dateien im aktuellen Verzeichnis mit Unterverzeichnissen

Das sollte dann auch mindestens eine Datei (Name der Batch) in den Schleifenkopf schicken.

demo.cmd

@echo off
for /f "delims=" %%a in ('dir "*.*" /a-d /b /s ') do (
  echo voller Name : "%%~a"
  echo nur Name.ext: "%%~nxa"
  echo lw:Pfad     : "%%~dpa"
  echo:
)
pause
1
Erzesel  07.10.2021, 21:28
@Destranix

so ..., jetzt habe ich meine Arbeit erledigt und kann mich deinem "Monster" widmen.

Hättest du auf Anhieb dabei gewusst

Anhieb ist bei jemanden wie mir ein relativer Begriff, ich mach das schon seit über 30 Jahren. Da weiß man einfach was man tut. Da hat man zig tausendmal die Regeln exerziert und muss nicht groß nachdenken...

Keine Ahnung wo Du das Ding ausgegraben hast?

Weshalb die äußeren "qoutes (und auch noch falsch) escaped wurden kann Dir nur der Schreiberling (Programmierer wäre geschmeichelt) sagen. Dublequotes werden in forfiles 0x22 escaped. und nur die inneren würden Sinn machen. In der Weise wie Du es hier gepostet hat ist das Ding völlige Schwachsinn.

Kein vernünftiger Mensch baut mit Forfiles solche Konstrukte. Ich verwende es bestenfalls mal als Datenlieferant , weil man damit Binärcodes generieren kann oder auf einen Zeitraum filtern kann. Als Ersatz für for kann das nicht herhalten. Forfiles ist lediglich für kleine Filter zu gebrauchen. Wenn wie in deinem Beispiel ganze Befehlsketten und auch noch innerhalb einer Zeile eine frisch gesetzte Variable aufgelöst werden soll wird es kompliziert. In dem Fall müssten die Ausrufezeichen für die verzögete Expansion auch noch escaped werden mit 3 carrets.(^^^!variable^^^!)

Allerdings ist es nicht möglich in einer Zeile ein einzelnes doublequote innerhalb eines echo zu tauschen, wenn Steuerzeichen folgen.

dazu muss man selbst in Batch mit einem Kunstgriff arbeiten:

set "variable=%variable:"=ersatz%

Die Anzahl an " muß immer innerhalb einer Zahle geradzahlig sein! (ein einigen Fällen ist der Interpreter tolerant, dann darf aber kein &Befehl oder |>Umleitung etc. folgen)

...und natürlich weiß ich wann ich &<>|! mit carret^ escapen muss. das ganze Regelwerk hier Aufzuführen würden den Rahmen sprengen. Wenn Du dich überzeugen willst, ob ich mich mit dem Kram auskenne, darfst Du gern meine "Spielwiese" besuchen: https://www.gutefrage.net/home/thema/batch-trick/neue

so sähe deine Forfile -Zeile aus damit sie funktioniert:

set "uniqueFileName=quak.txt"
FORFILES /m *.* /c "cmd /v:on /c set tmp_path=@path^& set 0x22tmp_path=^!tmp_path:0x22^='^^^! ^& echo file ^^^!tmp_path^^^! ^>^> %uniqueFileName%  ^& echo duration 1 ^>^>%uniqueFileName%"
pause

Zum testen habe ich *.png durch *.* ersetzt. wer hat denn überall png-Dateien rumliegen🤔

.

1
Destranix  08.10.2021, 07:51
@Erzesel
Keine Ahnung wo Du das Ding ausgegraben hast?

Selbst geschrieben, als ich mir ein Script schreiben wollte, das mit ffmpeg Bilddateien zu einem Video zusammenfügt. Dafür muss ich erst einen File erstellen, der angibt, welche Bilddateien dafür verwendet werden und wie diese zu verwenden sind. Die angegebene Codezeile tut das.

Anhieb ist bei jemanden wie mir ein relativer Begriff, ich mach das schon seit über 30 Jahren.

Ist mir schon klar. Das macht es doch wesentlich interessanter.

Ich selbst hatte mir das mühsam mit Hilfe des Internets gefrickelt und hat viel zu lange gedauert, dafür, dass das eigentliche in ganz simpler Task ist.
Meine Erfahrungen mit Batch halten sich in Grenzen, allerdings habe ich, was Programmiersprachen generell angeht, ein professionelles Vorwissen.

In der Weise wie Du es hier gepostet hat ist das Ding völlige Schwachsinn.

Ja gut, so sieht es auch aus. Aber es tut, was es soll interessanterweise. (Hätte ich vielleicht dazu schreiben sollen)

Kein vernünftiger Mensch baut mit Forfiles solche Konstrukte.

Nun, ich denke das erklärt die Schwierigkeiten. Ich bin offensichtlich irre ;-)

Aber woher weiß das jemand, der keine Ahnung von Batch im speziellem hat? Intuitiv ist das nicht gerade (leider).

0
Erzesel  08.10.2021, 09:53
@Destranix

Das schlimme wenn man rumgoogelt, man bekommt auch viel Mist serviert.

Mit einer ganz normalen for-schleife wär's ganz einfach gewesen 🥱

png2mp4.cmd

@echo off
set "framerate=24"
 rem hier pfad zu den Bildern
cd /d "F:\101CANON new"

 rem hier gewünschtes Dateimuster (hier alle img_0 mit folgenden 3Zifern)
(for %%a in (img_0???.png) do @(echo file '%%~fa')) > "images.txt"
 
rem pfad zu ffmpeg.exe anpassen
"c:\Program Files\Shotcut\ffmpeg.exe" -r %framerate% -f concat -safe 0 -i images.txt -vf scale=720:-2 -c:v libx264 -preset fast -crf 18 video2.mp4
pause



1
Destranix  08.10.2021, 10:28
@Erzesel

Ist leider zu lange her, dass ich das geschrieben habe, sonst könnte ich sagen, wieso ich keine normale For-Schleife verwendet habe.

0
Jan0000 
Fragesteller
 08.10.2021, 15:35
@Erzesel

OMG vielen Dank! Das ist meine Lösung!!!

1
Oh Gott, Oh Gott was machst du da. Mach das ganz anders!

Ich würde dir empfehlen, die altmodischen Batch-Scripte gar nicht mehr anzufassen und stattdessen auf das mittlerweile auch schon 15 Jahre alte Powershell umzusteigen. Das ist (soweit ich weiß) bei jedem Windows-PC automatisch dabei und dein Problem ist da drin ein Einzeiler.

$ordnerliste = Get-ChildItem -Recurse -Filter "*oem*.inf" -File -ErrorAction SilentlyContinue | Select DirectoryName
Erzesel  07.10.2021, 12:29

wenn ich nur den letzet Ordnernamen wissen möchte reicht auch die Console 😅

for /f "delims=" %a in ('dir "*oem*.inf" /a-d /b /s ') do (set "myFolder=%~dpa")
1
Erzesel  07.10.2021, 12:45

die Ordnerliste würde ich in eine Datei schreiben oder gleich im do-block verarbeiten..

diese macht das gleiche wie Deine Zeile

(for /f "delims=" %a in ('dir "*oem*.inf" /a-d /b /s ') do @(echo %~dpa))>Ordnerliste.txt

Powershell hat auch so seien Tücken, darüber sollte man nicht hinwegsehen..., das merkt man natürlich nur, wenn man mit etwas mehr als Deiner "Banalzeile" arbeitet.

0