dctibi
Goto Top

Entwerten von Sonderzeichen, die durch Dateinamen in eine Batch-Variable kommen...

Hallo, immer wieder habe ich in einer Batch Probleme mit Sonderzeichen - Leertasten an umöglichen Stellen, alle Arten von Klammern, Klammeraffen, Prozentzeichen, Ausrufezeichen, etc. face-sad

Habe hier schon mal auf Korrektur aller falschen Dateinamen auf einem Laufwerk geschrieben - der ursprüngliche Artikel dürfte aber zu alt sein, als das sich das noch wer anschaut?!

Deshalb hier noch mal - denn ich bin mir sicher, das Problem haben bzw. hatten viele und ist sicherlich gar nicht so schwer zum lösen - wenn man nur mal weiss, wie face-wink

Beispielsweise sollte untenstehende Batch NICHTS ausgeben - doch leider...

@echo off
setlocal enabledelayedexpansion
set "Basis=c:\temp"
cd /d %Basis%
echo Suche Dateien mit Zeichen, die in der Batch Probleme machen ab %Basis%...
for /f "usebackq delims=" %%a in (`"dir "\\?\%CD%\*" /b/s"`) do (
rem dc echo Teste "%%a"...
if not exist "%%a" echo Probleme mit einer Datei, in deren Namen %%a - aber dazu noch was doofes vorkommt...
)
echo Eigentlich sollte er nichts gefunden haben... doch bei kreativen Dateinamen gibt es leider sehr wohl Eintraege...
pause

Was muss man also machen bei solchen Dateinamen?

Content-ID: 224606

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

Ausgedruckt am: 22.11.2024 um 09:11 Uhr

rubberman
Lösung rubberman 16.12.2013, aktualisiert am 17.12.2013 um 14:00:29 Uhr
Goto Top
Hallo dctibi,

deine Probleme sollten sich mit folgender Kombination lösen lassen:
  • Zuweisung eines Variablenwertes bei ausgeschalteter verzögerter Variablenerweiterung
  • Arbeiten mit dem Variablenwert bei eingeschalteter verzögerter Variablenerweiterung

ungetestet:
@echo off
setlocal DisableDelayedExpansion

for /f "delims=" %%i in ('dir /a-d /b /s "c:\temp\*"') do (  
  set "filename=%%i"  

  setlocal EnableDelayedExpansion
  if not exist "!filename!" echo Dateiname "!filename!" macht Probleme.  
  endlocal
)

pause
Grüße
rubberman
dctibi
dctibi 16.12.2013 um 18:18:58 Uhr
Goto Top
Hallo Rubberman!

Sieht nicht nach einer Lösung aus face-sad

Habe jetzt nur wenige Testdateien angelegt - Dateinamen, die mit einem ! beginnen, werden weiterhin als falsch ausgegeben face-sad((
Endoro
Endoro 16.12.2013 um 18:55:47 Uhr
Goto Top
Hey,
du könntest deine Frage präzisieren:
- was ist die Eingabe
- was ist die erwartete Ausgabe
lg.
rubberman
rubberman 16.12.2013 um 19:33:53 Uhr
Goto Top
Hallo dctibi,

ich habe mal ein "C:\Temp" bei mir angelegt und eine Datei "!%&@ ^äß(1).#" hinein gelegt. Dann meinen Batchcode um eine Zeile erweitert, damit man auch sieht, was gefunden wurde.

@echo off
setlocal DisableDelayedExpansion

for /f "delims=" %%i in ('dir /a-d /b /s "c:\temp\*"') do (  
  set "filename=%%i"  

  setlocal EnableDelayedExpansion
  echo "!filename!" wird verarbeitet.  
  if not exist "!filename!" echo Dateiname "!filename!" macht Probleme.  
  endlocal
)

pause

Die Ausgabe:
"c:\temp\!%&@ ^äß(1).#" wird verarbeitet.
Drücken Sie eine beliebige Taste . . .

Ich kann deinen Einwand leider nicht nachvollziehen.

Grüße
rubberman
Friemler
Lösung Friemler 16.12.2013, aktualisiert am 17.12.2013 um 13:59:35 Uhr
Goto Top
Hallo dctibi,

ich habe mir vor einigen Jahren in einem masochistischen Anfall face-wink selbst eine Aufgabe gestellt, deren Problematik in die gleiche Richtung ging: Einen Fileselector in native Batch. Den Code habe ich später mal in diesem Thread gepostet (mein zweiter Kommentar dort). Ich konnte das Problem damals mit viel Mühe und Tricksereien lösen.

Der Code ist jetzt ca. 6 Jahre alt, ich kann Dir keine Einzelheiten mehr dazu erläutern, evtl. kannst Du Dir zumindest Anregungen herausziehen.

Was mir dazu noch im Gedächtnis geblieben ist:
  1. Ich habe so weit wie möglich versucht, auf die verzögerte Variablenerweiterung zu verzichten, da man dann zwar alle "üblichen Problemkandidaten" vom Hals hat, dafür aber mit dem Ausrufezeichen kämpfen muss.
  2. Wenn die verzögerte Variablenerweiterung ausgeschaltet ist, kann der Inhalt von Laufvariablen der FOR-Schleife mit ECHO ausgegeben werden, in einer anderen FOR-Schleife benutzt werden, als Argument an einen Befehl übergeben werden usw. Sonderzeichen werden dann brav übernommen.
  3. Probleme tauchen auf, sobald man den Inhalt einer FOR-Laufvariablen, die Sonderzeichen enthält, an eine normale Umgebungsvariable zuweist und damit irgendwelche Operationen ausführen möchte.
  4. Probleme gibt es auch, wenn man den Inhalt einer FOR-Laufvariablen an ein Unterprogramm übergeben will, und die Variable das Zeichen ^ enthält. Im Unterprogramm wird daraus ^^. face-sad
  5. Man kann aus einer FOR-Schleife ein Unterprogramm aufrufen und die Laufvariable der Schleife aus dem Hauptprogramm in einer FOR-Schleife im Unterprogramm verwenden (lässt sich mit Punkt 2 kombinieren).
  6. Man kann in einer FOR-Schleife die Laufvariable an eine normale Umgebungsvariable zuweisen und dann ein Unterprogramm aufrufen, in dem die Umgebungsvariable aus der FOR-Schleife im Hauptprogramm den aktuellen (vorher zugewiesenen Wert) hat. Damit kann man die (normale) "sofortige" Variablenerweiterung des Batch-Interpreters austricksen.
  7. Ich musste manchmal Abschnitte in den Code einbauen, in denen ich die verzögerte Variablenerweiterung temporär eingeschaltet habe (mit setlocal enabledelayedexpansion). Um am Ende eines solchen Abschnitts die geänderten Werte von Variablen aus diesem Abschnitt herauszubekommen, muss man folgendes Konstrukt verwenden:
set "x=Wert1_von_x"  
set "y=Wert1_von_y"  
setlocal enabledelayedexpansion
.
.
.
set "x=Wert2_von_x"  
set "y=Wert2_von_y"  
endlocal & set "x=%x%" & set "y=%y%"  
Zeile 9 muss genau so notiert werden, damit man die veränderten Werte von x und y nach diesem Block wieder zur Verfügung hat.

Für dieses Problem gibt es leider keine allgemeingültige Antwort, da die Wahl der Mittel stark davon abhängt, in welchem Kontext man was erreichen möchte.

Viel Erfolg bei Deinen Versuchen
Friemler


[Edit]
BTW: Die folgende Sammlung von Dateinamen
!Hallo!.TXT
!Hallo&Welt!.TXT
!Hallo.TXT
%Hallo^&^,;_^~'^Welt&&&.TXT
&^^&%%Hall!o^^^&W%elt&^&^^&&^^.TXT
^!Hallo^&Welt%%^^.TXT
Hallo%Welt.TXT
lässt sich mit diesem Batchscript ausgeben:
@echo off & setlocal

set "Basis=E:\Test"  

cd /d "%Basis%"  

for /f "delims=" %%a in ('dir /s /b "%CD%\*"') do (  
  echo %%a
)
[/Edit]
dctibi
dctibi 17.12.2013 um 13:52:13 Uhr
Goto Top
Hallo Rubberman, mit Leertasten am Ende bekommt man da leicht wieder eine Fehlermeldung hin. Aber Danke für deinen Code - hat mir weitergeholfen.

Generelle Frage, die wohl von allgemeinen Interesse ist: EnableDelayedExpansion ist, wie der Name meiner Meinung nach nicht vermuten läßt, die Ursache, warum Dateinamen mit besonderen Zeichen bei Befehlen wie copy, move, rename, etc. Probleme macht? Das einfach vermeiden bei allen Programmierungen (was ich hier aber noch nie gesehen habe) - und man wird mit seiner Batch egal bei welcher Dateinamen-Kreativität glücklich? Habe ich das richtig verstanden?
dctibi
dctibi 17.12.2013 um 13:59:19 Uhr
Goto Top
Danke, das in der Zeile 9 ist ein guter Ansatz meiner Meinung nach...

Und, ja, Friemler, ich denke, du bist masochistisch face-wink

Bin ich aber vielleicht auch. Ich war immer der Meinung "keep it simple and stupid" - also löse soweit es geht immer mit der Batch... doch die Batch ist doch sehr, sehr, sehr eigen... bin mir gar nicht mehr so sicher, ob simple = batch passt (nur stupid = batch *g*) face-wink
rubberman
Lösung rubberman 17.12.2013, aktualisiert am 18.12.2013 um 11:01:14 Uhr
Goto Top
Hallo dctibi.

Auch Leerzeichen am Ende des Dateinamens führen bei mir unter keinen getesteten Umständen zum Fehlschlag. Vielleicht magst du ja doch noch das eine oder andere Beispiel zeigen, bei dem du Probleme hast. Ich bin überzeugt es lässt sich lösen, solang nicht der Unicode-Zeichensatz angezogen werden müsste um die Dateinamen zu verarbeiten.

Was das Delayed Expansion angeht, so ist das erst einmal ganz einfach erklärt (darin bin ich geübt, hatte ich letzthin erst getan). Ich zitiere mich also mal selbst face-wink
Das setlocal EnableDelayedExpansion schaltet die verzögerte Variablenerweiterung ein.
In einer Kommandozeile oder einem in Klammern eingefassten Block von Kommandozeilen (zB. in einer FOR Schleife) werden normale Umgebungsvariablen nur einmal zum Wert aufgelöst, und zwar noch bevor die Zeile/der Block ausgeführt wird. Das EnableDelayedExpansion verzögert diese Auflösung, sodass die Werte zur Laufzeit der Zeile/des Blocks abgreifbar sind. Die umschließenden Prozentzeichen für die Variable sind dabei durch Ausrufezeichen zu ersetzen.
Beispiel zur Verdeutlichung:
@echo off

setlocal
set "n=vorher"  
for /l %%i in (0 1 4) do (
  set "n=%%i"  
  echo %n%
)
endlocal

echo ~~~~~~~~~

setlocal EnableDelayedExpansion
set "n=vorher"  
for /l %%i in (0 1 4) do (
  set "n=%%i"  
  echo !n!
)
endlocal

pause
Ende des Zitats.

Nun hat die verzögerte Erweiterung aber noch ein paar Sideeffects. Ausrufezeichen werden (sofern sie nicht maskiert wurden) bei Wertzuweisungen mal eben eliminiert. Schlimmer wird es noch, wenn ein String in Ausrufezeichen eingefasst ist, dann wird versucht diesen als Variable zu interpretieren. Das ist der Grund, warum die Zuweisung des Wertes bei ausgeschalteter verzögerter Variablenerweiterung erfolgen sollte, nach Schema
SET "Variablenname=Wert"
Die Anführungszeichen nicht vergessen, sonst gibt's wahrscheinlich unangenehme Überaschungen bei Sonderzeichen.
Warum dann aber für die Ausgabe/Verarbeitung einschalten? Ein Grund steht schon oben: Innerhalb der Schleife lässt sich die Variable sonst nicht zum Wert auflösen. Ein weiterer Aspekt ist, dass auch Sonderzeichen auf diese Art gefahrlos verarbeitet werden können, da diese für den Kommandozeileninterpreter beim Parsen des Codes noch nicht sichtbar sind.
Wie der Kommandozeileninterpreter mit Batchcode umgeht, lässt sich dort nachlesen.

Grüße
rubberman