Batch Schleife in Schleife, was mache ich falsch?
Moin,
ich versuche über einen bekannten Dateinamen von zwei Dateien den jeweiligen Überordner mit Pfad als Variable zu speichern.
Dazu fiel mir nur ein die gesuchte Datei temporär umzubenennen, einen Ordner mit dem Namen zu erstellen und in diesen mit CD zu wechseln.
Dann kann ich mit cd.. eine Ordnerebene zurückspringen und habe den gesuchten Pfad.
Nun muss ich noch den Pfad als Variable speichern.
%cd% gibt leider nicht den aktuellen Pfad sondern den Pfad vor begin der ersten Schleife aus.
Meine Alternatividee war:
for /f %%i in ('cd') do Set drv="%%i"
jedoch bleibt die Variable "drv" leer...
Hat jemand eine Idee?
@echo off
REM suche nach Treiber .inf Dateien mit "oem" im Namen um den richtigen Pfad zu finden.
REM dabei steht %%a für den Pfad zur .inf Datei.
for /f "delims=" %%a in ('dir "*oem*" /a-d /b /s ^| findstr.exe /l /i /c:.inf') do (
REM Trick um die richtigen Ordner als Pfad zu speichern:
REM zunächst umbenennen der .inf Datei in temp.tmp (später zurück benannt.)
ren "%%a" temp.tmp
REM Erstellen eines Ordners mit dem Namen der .Inf Datei.
mkdir "%%a"
REM welchseln in diesen Ordner und einen Schritt zurück gehen in den Überordner mit cd..
cd "%%a"
cd ..
REM den Pfad des überordners als Variable "drv" speichern.
for /f %%i in ('cd') do Set drv="%%i"
echo variable cd ist %cd%
echo variable drv ist %drv%
REM Hier ist der Fehler, dies klappt nicht.
pause
cls
REM löschen des Ordners mit dem Namen der .inf Datei.
rd "%%a"
REM umbenennen rückgängig machen.
ren temp.tmp "%%a"
2 Stimmen
3 Antworten
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")
Was genau willst du machen? Dir ist schon klar, dass du den Pfad, an dem eine Datei liegt, ganz einfach erhalten kannst, oder?
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....
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.
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
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🤔
.
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).
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
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
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")
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.
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?