Variable in If abfrage ändern und ausgeben?

2 Antworten

Guten Morgen :)

Du bist gerade auf ein Phänomen getroffen, auf das früher oder später jeder trifft, der Batchdateien schreibt.

Du musst dazu nachvollziehen, wie deine Batchdatei ausgeführt wird. Zunächst reicht es aber dies auf folgende Reihenfolge zu verkürzen:

  1. Zeile/Block wird eingelesen
  2. Variablen werden durch ihre Werte ersetzt
  3. Der Befehl/Die Befehle werden ausgeführt

Bevor die Zuweisung "set a=3" ausgeführt wird, wurde schon das im gleichen Block auftauchende Vorkommen der Variablen %a% durch den zu dieser Zeit aktuellen Wert von a, also 2, ersetzt.

Um das von dir erwartete Verhalten zu bekommen, hast du mehrere Möglichkeiten, die alle erreichen, dass %a% verzögert ersetzt wird:

(i) mit call:

set "a=2"
if %a% equ 2 (
    set "a=3"
    call echo.%%a%%
) else (
    set "a=2"
    call echo.%%a%%
)

Hierbei wird %a% nicht gleich durch 2 ersetzt, da die Prozentzeichen durch Doppelung escaped werden.

(ii) mit call einen Code außerhalb des Blocks aufrufen:

set "a=2"
if %a% equ 2 (
    set "a=3"
    call :printA
) else (
    set "a=2"
    call :printA
)
pause
exit

:printA
echo.%a%
exit /b

Statt nur a auszugeben, kannst du dort auch mehrere Befehle ohne die Einschränkungen des Blocks ausführen.

(iii) Mit Verwendung von delayedExpansion, durch die Variablen mit Ausrufezeichen verzögert ausgewertet werden können:

setlocal EnableDelayedExpansion
set "a=2"
if %a% equ 2 (
    set "a=3"
    echo.!a!
) else (
    set "a=2"
    echo.!a!
)

Hab noch keine Lösung. Aber das ist wirklich ein interessantes Phänomen. Innerhabl des ersten Anweisungsblock ignoriert er das SET bei der Ausgabe der Variable, erst nach Ausführugn der gesamten IF Anweisung ist dann der richtige Wert gesagt. ich kann das bei mir nachstellen.

Mein erster Verdacht war, dass der die Befehle piped. Also wie ein "echo j|del ordnername" die Abfrage nach Löschugn des Ordners automatisch mit ja bestätigt. Da steht der 2. Befehl vor dem ersten. Aber das passt hier nicht. Auch wenn das SET nach dem ECHO steht, ändert das nichts an der Ausgabe.

Mein Verdacht aktuell: das hat was mit der Art zu tun wie die IF Anweisung verarbeitet wird. Also was mit globaler und privater Variable. Erst nach Beendigung des IFs wird ggfls. der Wert der privaten Variable in die globale übertragen. Die ECHO Anweisung greift vielleicht automatisch immer die globale Variable ab.

Nicht das Batch sowas kann, aber der Compiler wird das so vermutlich umsetzen. SET platziert ja quasi eine Umgebungsvariable, die "global" für die DOS-Batch gilt solange die Shell aktiv ist.

Ist natürlich ein saudoofs Verhalten.

Also entweder das ECHO rausnehmen und nach dem IF Block ausführen, dann klappt es wunderbar, oder den Wert in eine neue temporäre Variable übertragen - das klappt zumindest bei mir hervorragend:

---------------------------------------------------------------------------------------

@echo off

set a=2

if %a%==2 (

  set t=3

  echo %t%

) else (

 set t=2

  echo %t%

)

set a=%t%

echo %a%

pause>nul

---------------------------------------------------------------------------------------

Kommt bei mir wie erwartet: "3 3" raus.

timlg07  30.04.2020, 10:15

Nein, das liegt nicht an irgendwelchen Sichtbarkeiten von Variablen. Wenn du z.B. folgendes schreibst:

set a=2
(
    set a=3
    echo.%a%
)

Dann wird das im Grunde so ausgewertet (ein Block wird quasi wie eine Zeile behandelt):

(
    set a=3
    echo.2   :: Der Inhalt von a ist zur Ausführungszeit dieser 
             :: Zeile schon 3, allerdings wurde %a% schon vor 
             :: Ausführung von set a=3 durch den String 2 ersetzt.
)

Also: erst werden alle Variablen durch ihren Inhalt ersetzt, dann wird der Block Befehl für Befehl ausgeführt.

Genauso verhält es sich bei folgendem Code:

set a=2
set a=3 & echo.%a%
0