Ein Symlink oder nicht?

Manaplayer

Cadet 4th Year
Registriert
Juni 2017
Beiträge
105
Hallöchen Leute,
Ich versuche es nun schon seit mehreren Stunden, aber finde einfach nicht heraus was hier dran verkehrt ist:

Code:
IF exist .\Audio\Winamp\Winamp.m3u (

FOR /f "tokens=3" %%a in ('DIR .\Audio\Winamp^|Findstr /i /m "Winamp.m3u\^>"') do (echo %%a >%TEMP%\suche.txt)

Findstr /c:SYMLINK %TEMP%\suche.txt)

IF %errorlevel%==1 (

del .\Audio\Winamp\Winamp.m3u

mklink .\Audio\Winamp\Winamp.m3u %TEMP%\Winamp.m3u) else (echo >nul)

IF not exist .\Audio\Winamp\Winamp.m3u (

mklink .\Audio\Winamp\Winamp.m3u %TEMP%\Winamp.m3u) else (echo >nul)

DEL %TEMP%\suche.txt

Der Batch soll herausfinden ob eine Datei existiert, und wenn ja, dann in welcher Form.
Das ganze noch leicht umständlicher, weil es die selbe Datei im selben Verzeichnis nochmal mit "Winamp.m3u8" gibt.
Das ganze bleibt aber schon in der ersten Zeile stehen, weil nichts für das echo gefunden wird (Verzeichnis und Datei werden aber
mit reinem "Dir-Befehl" aber gefunden)

Warum wird also nichts für das "echo" gefunden, um es der "suche.txt" zu geben? Alles geht bei "errorlevel" weiter, weil die "suche.txt"
nicht erstellt wurde und dann natürlich auch nicht gefunden werden konnte.
 
Zuletzt bearbeitet:
Mir ist noch nicht so ganz klar was genau du mit der FOR-Schleife bezweckst. Das sieht unnötig kompliziert aus Sollen da einfach nur alle Winamp.m3u* Files ausgegeben werden?

Das geht auch einfacher:

Code:
FOR /f %%a in ('dir /b .\Audio\Winamp\winamp.m3u*') do (
   echo %%a
)
 
Ja, die Schleife soll erst mit dem "DIR" die Liste aufmachen, und direkt danach "Findstr" auslesen ob die Datei drinstehen hat, ob es ein Symlink ist oder nicht.
Wenn das Wort "Symlink" in der Liste für die Datei nicht gefunden wurde, aber die die Datei schon, soll es bei errorlevel 1 weitermachen und sich um die Datei kümmern.
 
Ohne die "For-Schleife" funktioniert aus, wenn ich es im Fenster selber eingebe, aber als Script bleibt es schon in der Zweiten Zeile einfach stehen - Warum?

Code:
IF exist %Tools%\Audio\Winamp\Winamp.m3u (
dir %Tools%\Audio\Winamp|Findstr /i /m "SYMLINK"|findstr /i "Winamp.m3u\>")
IF %errorlevel%==1 (
del %Tools%\Audio\Winamp\Winamp.m3u
mklink %Tools%\Audio\Winamp\Winamp.m3u %TEMP%\Winamp.m3u)
echo Hat es funktioniert?
pause
 
also ich war gerade überrascht, dass man in der standard cmd überhaupt pipen kann... wohlgemerkt bin ich kein Batch Profi. Jedenfalls verstehe ich deine zweite Zeile nicht. Dort pipest du 2x hintereinander und ich verstehe nicht genau, wonach du suchst. zudem bin ich mir auch nicht sicher, ob "Winamp.m3u\>" so richtig ist. Wofür steht das \> ?
 
Also nochmal - es soll erstmal nur ein Test sein, für später mehrere Symlink-Dateien. Ich will mit dem Batch herausfinden, ob die jeweilige Datei überhaupt existiert, wenn ja, ob es eine zum Beispiel echte mp3-Datei ist, oder eine Symbolische Verknüpfung.
Um die Situation noch etwas schwieriger zu machen, handelt es sich um zwei Dateien im selben Verzeichnis:
"Winamp.m3u" und "Winamp.m3u8".
Das mit dem \> am Ende bei dem "findstr"-Befehl ist dafür da, dem Befehl das klare Ende des Wortes zu geben wonach gesucht werden soll.
Wenn ich nicht "Winamp.m3u\>" eingebe, werden beide Dateien als gefunden ausgegeben.

Die Sache läuft soweit ja schon fehlerfrei wenn ich den ganzen Code selber im Fenster eingebe, nur als Script, bleibt das ganze ohne weiteren Ausgaben einfach in der ersten Zeile stehen.
Ich hoffe ich kann den Grund, warum ich drei Befehle hintereinander verwende somit erklären:
Der erste "Dir-Befehl" einfach, um die Ausgabe zu haben was für Dateien im Vergeichnis sind. Wenn eine der Dateien eine Symbolische Verknüpfung ist, wird vor der Datei zusätzlich "<SYMLINK>" in der Zeile ausgegeben.
Der zweite Befehl "findstr "symlink"" soll erstmal schauen, ob überhaupt eine symlink Datei vorhanden ist und mit der ausgegeben Liste damit aussortieren.
Der dritte Befehl "findstr "Winamp.m3u\>" soll dann bestätigen dass es sich bei den aussortierten Dateien um eine exakt "Winamp.m3u" Datei (symbolische Verknüpfung) handelt. Wenn sie bestätigt werden konnte, ist alles ok und kann ohne ERRORLEVEL weitergehen, wenn es aber nicht bestätigt werden konnte (errorlevel 1), soll sie damit eben erst erstellt werden.

Nur kommt es ja gar nicht erst zu der errorlevel-Zeile. Das ist das Problem...
 
Hm.. Eine Lösung habe ich zwar spontan nicht, aber Batch ist hier vielleicht generell das falsche Werkzeug. Schau dir doch sonst mal PowerShell an. Hier ist ein Beispiel wie man einen Symlink in PS erkennt: Klick!

Batch ist eigentlich nur ein großer Haufen Mist und eignet sich sogesehen wirklich nur dazu, um stuide eine Reihe von wiederkehrenden Kommandos abzufrühstücken. Alles was darüber hinausgeht ist in Batch nicht gut aufgehoben, weil selbst die banalsten Dinge zu komplex umzusetzen sind und teilweise auch regelrecht gegen den gesunden Menschenverstand verstoßen.
 
  • Gefällt mir
Reaktionen: DubZ
Nun, es mag einfacher sein, aber ich möchte nicht zwei Programmier-Arten auf einmal lernen. Bei der Sache mit Powershell hat man es vielleicht sofort herausgefunden ob es ein Symlink ist oder nicht, aber dann...? Wie geht es weiter mit errorlevel oder nicht? Bei Powershell stehe ich noch bei Lernlevel 0%
 
Gerade der errorlevel ist bei batch ein schwieriges Thema. Es ist nicht sicher, dass der errorlevel überhaupt gesetzt wird und zB ERRORLEVEL und %errorlevel% sind nicht dasselbe! Bei batch kann es durchaus vorkommen, dass eine Anwendung ERRORLEVEL setzt, aber %errorlevel% eben nicht.

Wie auch immer, wenn du es unbedingt mit Batch lösen willst, solltest du zunächst die Kommando-Teile in der Schleife einzeln testen. Zunächst also erstmal prüfen ob dir überhaupt die richtigen Dateien auflistet.
 
Alles mit Fenstereingabe gestestet, das errorlevel ist auch immer korrekt (zum test jede art von der Datei geändert). Bei der Art mit "for-schleife" bleibt das ganze eben bei der genau in der Zeile einfach stehen, ohne irgendwelche Ausgaben.
Dass ich drei Befehle direkt hintereinander brauche, ist eben, weil der zweite Befehl nur die Ausgabe des ersten Befehls ausliest und so weiter.
 
Ich weiß was pipen bedeutet. Das Problem ist aber nun mal, dass man da nicht reingucken kann. Daher kann man nur Schritt für Schritt das for-Kommando aufbauen und testen ob bis dahin überhaupt das richtige ankommt.

Bei Batch sind es zwei Paar Schuhe ob man etwas in der Kommandozeile eingibt oder es als .bat ausführt. Deswegen ist es nur bedingt hilfreich, wenn es in der Kommandozeile funktioniert, in der Batch jedoch nicht. Daher der Schritt-für-Schritt-Test des Kommandos in der batch.

Ansonsten kannst du die for-Schleife notfalls auch aufdröseln und zB temporäre Dateien erstellen, in denen nur die gewünschten Dateinamen aufgelistet sind. So kann findstr zB mit dem Parameter /f eine Dateiliste aus einer Datei auslesen.

Ohne jedweden Anspruch auf Vollständigkeit, nur zur Darstellung was gemeint ist:

Code:
dir /b winamp.m3u*>winampfiles.txt
findstr /i /m /f:winampfiles.txt "symlink"
del winampfiles.txt

Übrigens: Soweit ich weiß wird findstr den gepipten Input nur als reinen Text ansehen und dann durchsuchen, nicht jedoch als Dateiliste interpretieren und dann eben in diese Dateien jeweils reinschauen. Kann mich aber auch irren, hab's nicht getestet.
 
Jetzt funktioniert es - Das Script gab ständig ERRORLEVEL 0 aus, egal nach welchem Wort gesucht werden sollte, was überhaupt gar nicht in den Listen stand. Wenn nach dem Errorlevel innerhalb der "IF exist-Klammer" gefragt wurde, war es immer Errorlevel 0, egal wie falsch es auch war. Ausserhalb stimmt das jeweilige Errorlevel wieder, und die ganze Sache läuft jetzt korrekt:

Code:
IF exist %Tools%\Audio\Winamp\Winamp.m3u (
dir %Tools%\Audio\Winamp\Winamp.m3u* >%TEMP%\test.txt
for /f "tokens=4" %%a in ('findstr /i "SYMLINK" %TEMP%\test.txt') do (echo %%a >>%TEMP%\test2.txt)
findstr "Winamp.m3u\>" %TEMP%\test2.txt)
IF %errorlevel%==1 (
del %Tools%Audio\Winamp\Winamp.m3u
mklink %Tools%\Audio\Winamp\Winamp.m3u %TEMP%\Winamp.m3u)
::
IF exist %Tools%\Audio\Winamp\Winamp.m3u8 (
dir %Tools%\Audio\Winamp\Winamp.m3u* >%TEMP%\test.txt
for /f "tokens=4" %%a in ('findstr /i "SYMLINK" %TEMP%\test.txt') do (echo %%a >>%TEMP%\test2.txt)
findstr "Winamp.m3u8\>" %TEMP%\test2.txt)
IF %errorlevel%==1 (
del %Tools%Audio\Winamp\Winamp.m3u8
mklink %Tools%\Audio\Winamp\Winamp.m3u8 %TEMP%\Winamp.m3u8)
::
del %TEMP%\test.txt
del %TEMP%\test2.txt
 
Darauf wollte ich hinaus als ich sagte, dass ERRORLEVEL und %errorlevel% unzuverlässig sind. Man muss vorsichtig sein, wenn man sein Skript explizit darauf aufbaut.

Batch eignet sich daher weitestgehend nur für reine Aufgaben wo man einen Stapel von Befehlen - den namensgebenden Batch - abarbeiten will. Als Scriptsprache ist Batch zwar nicht unbrauchbar, aber es gibt einfach zuviele Spezialfälle, in denen sich Batch einfach nicht so verhält wie man es von anderen Script- oder gar Hochsprachen gewohnt ist.


Was mir an deinem Skript gerade noch auffällt ist die inkonsistente Verwendung von %Tools%. Entweder Tools wird ohne abschließendes \ belegt und dann %Tools%\bla\blubb genutzt oder man setzt es mit abschließendem \ und verwendet dann %Tools%bla\blubb. Ich bevorzuge ersteres, weil im zweiten Beispiel nicht klar erkennbar ist, dass es sich um einen Pfad handelt. In #14 fehlt bei dir das \ und deswegen wird der Befehl wohl auch fehlschlagen, weil du sonst immer %Tools%\ nutzt und die Variable Tools dann mutmaßlich mit SET Tools=c:\irgendein\pfad gesetzt wurde, ohne \ am Ende.

Darüber hinaus solltest du bei IF %variable%==xyz immer Anführungszeichen drumherumpacken. IF "%variable%"=="xyz". Das ist nämlich wieder so eine Besonderheit von Batch, weil %variable% eine reine Textersetzung ist. Das heißt, wenn die Variable leer ist, steht da sonst IF ==xyz und dann crasht das Skript.

Ich würde sogar noch einen Schritt weitergehen. So oft wie du %Tools%\Audio\Winamp\... verwendest, kannst du auch gleich noch ein SET %winamp%=%Tools%\audio\winamp setzen und dann sieht das schon aufgeräumter aus ;)


Wenn man's noch aufgeräumter haben will, packt man den ganzen Block in eine Funktion und ruft sie dann mit CALL einmal für die m3u und einmal für die m3u8 auf (die GOTO:EOF nicht vergessen!). Natürlich darf man auch eine Batch einrücken, um die Struktur zu verdeutlichen ;)

Code:
SET winamp=%tools%\audio\winamp

CALL:DOTHEWINAMP winamp.m3u
CALL:DOTHEWINAMP winamp.m3u8

GOTO:EOF


:DOTHEWINAMP
SET winampfile=%1
IF exist %winamp%\%winampfile% (
   dir %winamp%\%winampfile%* >%TEMP%\test.txt
   for /f "tokens=4" %%a in ('findstr /i "SYMLINK" %TEMP%\test.txt') do (echo %%a >>%TEMP%\test2.txt)
   findstr "%winampfile%\>" %TEMP%\test2.txt
)
IF "%errorlevel%"=="1" (
   del %winamp%\%winampfile%
   mklink %winamp%\%winampfile% %TEMP%\%winampfile%
)
GOTO:EOF

Bei der Abfrage des errorlevel bin ich mir übrigens nicht sicher ob damit das Ergebnis des vorangegangenen IF-Befehls heranzgezogen wird oder das Ergebnis aus dem letzten findstr. Der Errorlevel definiert sich nämlich immer durch den zuletzt aufgerufenen Befehl und bei Batch weiß man nie ob ein geklammerter Befehlssatz dann als ein Befehl gilt. Ergo könnte das errorlevel-if schlicht und ergreifend den false/true-case des if-exist abfragen. Müsstest du mal konkret ausprobieren. Wenn letzteres der Fall ist, kann man auch einfach so machen:

Code:
if exist %winampfile% (
   REM do some stuff
) else (
   REM do some other stuff
)

So, ich hoffe das war nicht zuviel Input. Natürlich kannst du das Skript so lassen, wenn es funktioniert, aber Luft nach oben gibt es immer, auch bei Batch. Gerade CALL kann ein Batch-Skript viel angenehmer gestalten, weil man den komplizierten Teil ganz unten hinter einer Sprungmarke versteckt und oben den ganz banalen Programmablauf sieht, die zwei CALL-Aufrufe für die beiden winamp-files.
 
Danke für Deine Mühe mit dem vielen Text.
Ja, dass die \ noch gefehlt hatten, hab ich gemerkt als ich den Text hier schon fertig hatte.
Da hatte ich nur auf das Ergebnis des Errorlevels geschaut.
Zusammen mit der Korrektur von den \ -Strichen läuft jetzt alles.
Den Code den ich hier ausgegeben habe, ist nur ein Teil eines ganzen Batch-Script, was mit einem Klick sich darum kümmern soll das System sauber und korrekt zu halten.
Der Fehler war nur bei dem ausgegebenen Teil hier.
Darum mache ich mir nicht die Mühe an jeder Zeile noch Kommentare und sonstiges miteinzuarbeiten.
Trotzdem Danke für eure Hilfe :)
 
Gerade wenn das Skript noch länger ist, sollte man sich besagte CALL-Funktion anschauen. Ein Skript wird deutlich übersichtlicher, weil man direkt den Ablauf sieht was passiert und nicht wie. Sonst verzettelt man sich in for-schleifen, if-abfragen und dergleichen.

Aber wie gesagt, das waren nur ein paar Anmerkungen wie man Batch-Skripte optimieren kann. Wenn's nu läuft wie es soll und du damit zufrieden bist, dann kann es natürlich auch so bleiben. Dümmer wird man aber zumindest nicht davon und hilft auch, wenn man dann eben doch mal den Sprung zu einer adäquaten Skriptsprache wagt.
 
Zurück
Oben