yashi
Goto Top

set /p innerhalb von if

fehlermeldung bei der kombi von if + set /p

hallo.
ich beschäftige mich, auf grund der notwendigkeit, seit 2 tagen mit dem batch syntax. nun habe ich ein kleines batchfile geschrieben, mit dem ich das starten von anwendungen kontrolliere, bei bedarf reg schlüssel auslese und falls diese nicht vorhanden sind, eine manuelle eingabe der benötigten daten starte.
nun habe ich schon google und das forum hier durchsucht, allerdings nur allgemeine sachen über set und if gefunden. aus der windows hilfe habe ich alles gelernt über die wichtigsten befehle, scheitere jedoch trozdem an einem scheinbar lächerlichem punkt. face-sad
hier erstmal der quellcode, den ich mit hilfe des cmd-fensters als fehlerhaft lokalisieren konnte:

 
@echo off & setlocal

set mdir=test
:: zwecks test in extra batchfile


if /i (%mdir%)==(test) (
echo here comes the menu
echo 1 bla
echo 2 bla
echo input ?
<font color="#ff0000">set /p msel=  
if (%msel%)==(1) set mdir=path1
if (%msel%)==(2) set mdir=path2
if (%msel%)==(3) set mdir=xy
if (%msel%)==(4) set mdir=path3
) ELSE (
echo auto-detected dir...
::noch paar andere cmds
)

::usw

echo.
echo mdir: %mdir%
pause
</font>

der cmd in rot wird nie ausgeführt.
der code gibt folgende meldung:
")" ist syntaktisch an dieser Stelle nicht verarbeitbar.  
C:\batch>if ()==(1) set mdir=path1
wenn ich die klammern weg lasse und/oder vorher einen wert für msel definiere geht es auch nicht bzw. es wird auf eine eingabe gewartet und dann doch der vordefinierte wert verwendet.
einzeln funktionieren ja die befehle (die if-prüfung für sich, sowie das menü mit eingabe für sich), aber zusammen eben nicht.... *schnief*
naja.... bin eben doch noch en ganz schöner nup...


mfg... das kleine yashi

Content-ID: 26294

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

Ausgedruckt am: 26.11.2024 um 10:11 Uhr

Biber
Biber 18.02.2006 um 13:51:07 Uhr
Goto Top
Moin yashi,

da scheint de CMD-Prompt wirklich ein Problem zu haben.. muss ich mir mal in Ruhe ansehen.

Das wäre dann ja schon Bug #4033 auf meiner Liste... *gg
Also - Du hast da nichts verkehrt gemacht und dokumentiert ist dieses Verhalten auch nicht.

Du kannst es auf mehrere Arten umgehen, empfehlen würde ich die wenig elegante mit "goto":

::------------------
echo off & setlocal
set mdir=test
:: zwecks test in extra batchfile
echo input ?

if /i [%mdir%]==[test] goto getAuswahl
goto autodetect

:getauswahl
echo here comes the menu
echo 1 bla
echo 2 bla
echo input ?
set /p "msel=bla"
if [%msel%]==[1] set mdir=path1
if [%msel%]==[2] set mdir=path2
if [%msel%]==[3] set mdir=xy
if [%msel%]==[4] set mdir=path3
goto undweiter

:autodetect
echo auto-detected dir...
::noch paar andere cmds

:undweiter
::usw
:: ....
::------------


Um andere Konflikte zu vermeiden, habe ich die "runden Klammern" bei den IF-Vergleichen durch eckige ersetzt. Runde Klammern sind eben auch Steuerzeichen im Batch... aber das hat mit dem SET /P-Effekt, der Dir aufgefallen war, nichts zu tun.

Gruß Biber
maneich
maneich 18.02.2006 um 19:48:23 Uhr
Goto Top
Hallo,

Probiere es mal mit

set /p msel=Eingabe:

andere Frage:

wenn ich diese Zeile in Deinem Thread markiere, hört sie nicht direkt hinter dem =-Zeichen auf, da sind noch 1 / 2 Leerzeichen dahinter.

Teste mal wie es aussieht wenn Du die Zeile direkt hinter " = " abschließt.

MfG maneich
Biber
Biber 18.02.2006 um 20:16:44 Uhr
Goto Top
@maneich

Stimmt, ich hatte es auch auf das "Set /p" geschoben.

Ursachen sind zwei:

1) beim ersten "Set mdir=... ist ein Leerzeichen dahinter.
Also steht da "in Wirklichkeit
Set "mdir=test " und das führt zu Fehlinterpretation bei
IF (test )==(test) ...
2) Zweite Ursache... Die runden Klammern als Trennzeichen in den IF-Vergleichen.

Folgendes Codefragment läuft (runde Klammern der IFs durch "x" ersetzt; SETs glattgezogen):


::--------------yashis.bat
@echo off & setlocal
set "mdir=test"
:: zwecks test in extra batchfile

if /i x%mdir%x==xtestx (
echo here comes the menu
echo 1 bla
echo 2 bla
echo input ?
set /p msel=
if x%msel%x==x1x set mdir=path1
if x%msel%x==x2x set mdir=path2
if x%msel%x==x3x set mdir=xy
if x%msel%x==x4x set mdir=path3
) ELSE (
echo auto-detected dir...
REM noch paar andere cmds
)

::usw

echo.
echo mdir: %mdir%
pause
::--------------yashis.bat

Gruß Biber
maneich
maneich 18.02.2006 um 20:30:39 Uhr
Goto Top
Hallo Biber,

freut mich wenns nun läuft.

Noch eine kleine Anmerkung:

eigentlich genügt es, wenn auf beiden Seiten der ==-Zeichen nur 1 Zeichen gesetzt wird, z.B. if %msel%'==1' set mdir=path1

In meiner Augen ist dies sehr viel übersichtlicher.

MfG maneich
yashi
yashi 24.02.2006 um 16:41:29 Uhr
Goto Top
hallo !

erstmal sorry für meine lange abwesenheit .... habt mich bestimmt schon vermisst ;)
danke an biber und maneich für euren support, aber es funktioniert leider immer noch nicht. da bei deinem letzten beispiel die zeilen die nach set /p kommen nie ausgeführt werden biber (im testlauf war "mdir" immer auf "test" gestellt und blieb es auch), werde ich wohl auf die "lösung" mit goto zurückgreifen müssen. ich hatte es schon mit call versucht, was allerdings auch nicht ging.
zu den leerzeichen in meinem code: das board scheint automatisch hinter jede zeile ein leerzeichen zu setzen.

falls irgendjem. noch eine idee hat .... das thema ist jetzt wieder warm ^^


#edit:
wenn ich 2 werte vergleiche, und diese in symbole einschließe, werden doch daraus strings oder ?
also dürfte dann sowas wie
if x%var%x LEQ x10x ....
nicht funktionieren ?! ..
Biber
Biber 24.02.2006 um 18:35:24 Uhr
Goto Top
Moin yashi,

schön, mal wieder von Dir zu lesen...

Also, wenn mein oben geposteter Batchschnipsel NICHT läuft, dann kommt es durch das Copy & Paste'n .. ersetze bitte die Zeile
ALT: set /p msel=
-durch-
NEU: set /p "msel="

Denn dann ist da wieder ein trailing blank hinter. Darauf wette ich alle Rosen, die ich zum Valentinstag geschenktz bekommen habe. face-wink

Die zweite Frage:
wenn ich 2 werte vergleiche, und diese in symbole einschließe, werden doch daraus strings oder ?
also dürfte dann sowas wie
if x%var%x LEQ x10x ....
nicht funktionieren ?! ..
Wie häufig bei M$-Programmen ein klares "Jein".

Die CMD.exe kennt nur Strings...eigentlich ... also weder den Datentyp "Datum" oder "Long" oder "Integer"....ABER:

Wenn einer der beiden verglichenen Werte "eindeutig" numerisch ist, d.h. über "Set /a" als Zahlenwert erzwungen, dann wird auch der zweite Wert auf Numerisch geCASTet.

Heißt in der Konsequenz allerdings auch wieder nur Wischiwaschi..(ist halt M$):
einen mit "Set /a" definierten Wert von "4711" kannst Du mit LSS,GEQ, GTR etc vergleichen...

Set /a "test=47"

if %test% LSS 77 @echo Ist kleiner!
Ist kleiner!

Aber auch einschließen....
if x%test%x LSS x77x @echo Ist kleiner!
Ist kleiner!


Und irgendwann ist es aber nicht mehr einleuchtend:
if x%test%x lss xeex @echo Ist kleiner!
Ist kleiner!

if %test% lss ee @echo Ist kleiner!
Ist kleiner!

if %test% lss 000000000 @echo Ist kleiner!

if %test% lss 47e @echo Ist kleiner!
Ist kleiner!

Deine Beispielzeile "if x%var%x LEQ x10x funktioniert also, aber ich würde sie schon so formulieren:
If %var% LEQ 10 Echo var ist kleiner gleich 10

-oder-
Set /a var+=0 >nul
If Errorlevel 1 (
echo Variable var hat keinen numerischen Wert!
) ELSE (
If %var% LEQ 10 Echo var ist kleiner gleich 10!
)

Schönes Wochenende
Biber
maneich
maneich 24.02.2006 um 18:58:36 Uhr
Goto Top
Hallo,

im grunde genommen setzt Du auf beiden Seiten der Abfrage ja das/die gleichen Zeichen ein, damit die Abfrage auch immer klappt. Existiert die Variable nicht, bekommst Du ohne zusätzliche Zeichen einen Syntaxerror.

Wenn Du also sicher sein kannst daß die Variable existent ist, brauchst Du diese zusätzlichen Zeichen nicht.

Warum das bei Dir nicht läuft, kann ich auch nicht sagen. Du kannst ja mal ff. versuchen:

if /i x%mdir%x==xtestx (
echo here comes the menu
echo 1 bla
echo 2 bla
echo input ?
set /p msel=
echo %msel%
pause

Um überhaupt mal zu wissen ob und was nach der Eingabe drinnsteht.

MfG maneich
yashi
yashi 25.02.2006 um 09:59:16 Uhr
Goto Top
wow. das geht ja schnell bei euch. ich enttäusche dich ja nur ungern biber, aber auf die überflüssigen leerzeichen hab ich geachtet und sie nach dem pasten per hand aus jeder zeile entfernt (bin bei sowas eigentlich immer aufmerksam) auch das
set /p "msel="
was ich mal zur sicherheit probiert hab, hat keine abhilfe geschaffen...

*schon mal an deinen rosen schnupper*

ich versteh nicht warum es bei dir geht und bei mir nicht face-sad

aber danke für die beantwortung der 2. frage ! und um so eine leere variable zu umgehen, könnte man doch auch alle vars die man so braucht in seiner batch am anfang "initialisieren"
zb so
@echo off & setlocal
set "var1=null"
set "var2=null"
set /a "var3=0"
...

naja sieht auch besser (übersichtlicher) aus, oder nich ?
... nur so ne idee


aber jetzt mal back @topic (hoffentlich mach ich euch nich müde damit)


ja maneich, deinen vorschlag hatte ich schon, aus debug gründen, in bibers letzten code eingebaut.


der dann also so aussieht:
@echo off & setlocal
set "mdir=test"

if /i x%mdir%x==xtestx (
echo menu.input ?
set /p "msel="
if x%msel%x==x1x echo 1
if x%msel%x==x2x set "mdir=path2"
if x%msel%x==x3x set mdir=path3
if x%msel%x==x4x ( set mdir=path4 )
) ELSE (
echo auto-detected dir...
)
echo mdir: %mdir%
echo msel: %msel%
pause
(die leerzeichen hat wieder das board hinzugefügt)


in jedem fall, bekomme ich für msel meine eingabe zurück (1, 2, 3, 4, hallo) und für mdir "test" ! d.h. es wird nie "echo 1" oder "set mdir=path3" ausgeführt. obwohl die werte überein stimmen.

könnte es also sein (und damit sind wir bei meiner eben aufgestellten theorie), dass konstruktionen, die nur unter bestimmten bedingungen ausgeführt werden (also cmds hinter if zb) vor der laufzeit bearbeitet werden (oder so) und deshalb nicht mehr richtig mit dem user interagieren können ?

folgendes experiment hat mich nämlich auf den gedanken gebracht:

@echo off
if 123==987 (
echo true
if if if ... i fail -.-
) ELSE (
echo false
)
echo end
echo.
pause

geht nicht und bricht mit syn error ab, obwohl
"if if if" nie erreicht werden dürfte sondern bei else
weiter gemacht werden müsste

@echo off
pause
goto 2
if if if ... i fail -.-
:2
pause

geht wunderbar face-smile
also gilt es wohl nur für code hinter if ?!


so genug gefachsimpelt. jetzt sind die gurus mal wieder dran


mfg
maneich
maneich 25.02.2006 um 11:49:30 Uhr
Goto Top
Hallo,

nun ja, die if...else Konstruktion ist in sich geschlossen 1 Befehlssatz und in Deinem letzten Beispiel ist die Syntax eben in diesem Befehlssatz falsch.

Ob dieser Befehlssatz über eine Zeile

if %a%==%b% (goto :x) else (goto :y)

oder über mehrere Zeilen, wie in deiner Batch, aufgebaut ist, ist dabei unwesentlich. Es ist und bleibt 1 Befehlssatz

Bei der goto ... Konstruktion wird die falsche Syntax-Zeile ungeprüft übersprungen, da dies dann ein neuer Befehlssatz ist.

Mache einfach mal folgendes:

@echo off

set mdir=test
:: zwecks test in extra batchfile


if not (%mdir%)==(test) goto nr2
echo here comes the menu
echo 1 bla
echo 2 bla
echo input ?
set /p msel=
if (%msel%)==(1) set mdir=path1
if (%msel%)==(2) set mdir=path2
if (%msel%)==(3) set mdir=xy
if (%msel%)==(4) set mdir=path3
goto usw
:nr2
echo auto-detected dir...
::noch paar andere cmds

:usw

echo.
echo mdir: %mdir%
pause

Mal sehen, was dann passiert. Der Parameter /i bei if ist in Deinem Fall nicht unbeding nötig. Das setlocal ebenfalls mal weglassen.

Ich denke, daß setlocal der Variablen zwar den Wert "test" übergibt aber ohne endlocal keine Änderung möglich ist. Würde ich mal als erstes testen in Deiner ursprünglichen Batch, ist hier auch nicht wesentlich.

MfG maneich
Biber
Biber 25.02.2006 um 12:35:50 Uhr
Goto Top
Moin yashi,

so was... erst tagelang nicht um angefangene Threads kümmern und dann auf meine Rosen schielen... *tztztz face-wink

Aber recht hattest Du - es lag diesmal nicht an trailing blanks - ich hätte mir auch die Mühe machen können, diese Schnipsel mal laufen zu lassen. Oder zumindest Deinen Titel laut und deutlich vor mich hinzusprechen. Das hab ich jetzt.

a) der Syntaxfehler bei "if if if --tilt" hat mich drauf gebracht: Auch wenn Dein IF (..)..ELSE (..) - Konstrukt über noch so viele Zeilen gestreckt ist - der CMD-Interpreter fasst es immer noch als eine Zeile auf.
Entsprechend liest er alles bis zur Klammer-Zu en bloc ein, macht seinen Syntaxcheck und führt es dann aus. Bzw. bei Dir kommt er eben nur bis zum Syntaxcheck und meckert dann. Zu recht. Nicht beim Ausführen, wie Du unterstellt hast, sondern einen Schritt vorher, beim Parsen, beim Syntaxcheck. Wenn Du ein "REM" vor das "if if if" setzt, dann passiert er den Syntaxcheck.

if 123==987 (
echo true
rem if if if ... i fail -.-
) ELSE (
echo false
)
echo end
echo.
pause

b) Und - dadurch, dass das IF-Konstrukt EINE Zeile ist, werden "natürlich" alle darin enthaltenen Variablen EINMAL, beim "Einlesen" der einen Zeile aufgelöst. Auch die Variable %msel%, die ja durch das "Set /p msel="einen neuen Wert bekommt. Der wird aber innerhalb der IF-Verzweigung nicht neu aktualisiert, es sei denn, bei Dir ist die so genannte verzögerte Variablenauflösung aktiviert.

So macht der Code-Schnipsel das was Du willst:
:: --- snipp yashisIfMselMitDelayedExpansion.bat
@echo off & setlocal EnableDelayedExpansion
set "mdir=test"

if /i x%mdir%x==xtestx (
rem --verschoben in das Set /p-- echo menu.input ?
set /p "msel=menu.input ?"
if x!msel!x==x1x echo 1
if x!msel!x==x2x set "mdir=path2"
if x!msel!x==x3x set "mdir=path3"
if x!msel!x==x4x set "mdir=path4"
) ELSE (
echo auto-detected dir...
)
echo mdir: %mdir%
echo msel: %msel%
pause
:: --- snapp yashisIfMselMitDelayedExpansion.bat


Entscheidend ist in der ersten Zeile: @echo off & setlocal EnableDelayedExpansion
...und etwas tiefer die !var! statt %var%-Syntax bei den Variablen, die Du "verspätet" auflösen willst.

( Anmerkung: die Änderung ..
rem --verschoben in das Set /p-- echo menu.input ?
set /p "msel=menu.input ?"
... hat inhaltlich nichts damit so tun... das war nur die Umsetzung von maneichs Anregung einen halben Meter weiter oben.)
Und das "Einschließen" der VBariablen mit einem beliebigen Buchstaben/Zeichen wie z.B. "x" war nur ein Beispiel.
Ich würde aus Lesbarkeitsgrunden nie schreiben:
if x!msel!x==x1x echo 1
if x!msel!x==x2x set "mdir=path2"
if x!msel!x==x3x set "mdir=path3"
if x!msel!x==x4x set "mdir=path4"

--sondern:
if [!msel!]==[1] echo 1
if [!msel!]==[2] set "mdir=path2"
if [!msel!]==[3] set "mdir=path3"
if [!msel!]==[4] set "mdir=path4"


HTH Biber

[Edit] @maneich
uuups, da warst ja zwischendurch schon wieder schneller.. na ja, ich habe nebenbei noch Mittagessen gekocht..*gg
Dein Kommentar war noch nicht da, als ich angefangen hatte..
[/Edit]
yashi
yashi 26.02.2006 um 17:38:27 Uhr
Goto Top
Genial. Wurde das Rätsel also doch noch gelöst. Hatte mich schon gewundert, dass mir vom Ober-Guru eine "goto" Lösung angeboten wird. Den Code hätte mir wohl jeder halbwegs bewanderte Programmierer um die Ohren gehauen ;)
Als ich sagte: "(If-Konstrukte werden vielleicht) vor der Laufzeit 'bearbeitet' [...]" wollte ich damit auf ein Verhalten hinaus, welches, wie ich jetzt erfahren habe, durch das sogenannte Parsen verursacht wird. (bzw. durch das parsen eines ganzen Befehlssatzes vor dem Ausführen). Konnte mich aber nicht verständlich ausdrücken, da ich ja keine Ahnung von der Funktionsweise und Benennung der internen Vorgänge hab.
Und wenn ich in Bibers Tutos noch so viel verstanden habe, über "EnableDelayedExpansion" musste ich immer wieder erfolglos grübeln.
Und damit hast Du nicht nur die mysteriösen Fehlermeldungen meiner Batch beseitigt, sondern auch die Wirkung von "EnableDelayedExpansion" an einem wunderbar nachvollziehbaren Beispiel erklärt. Deinem Beitrag verpass ich gleich mal 5 Sterne
Natürlich auch ein großes Danke an maneichs Bemühungen und Wegweiser !

Ich werd den thread mal als "gelöst" markieren.


verzögerte Variablenauflösung - Fluch, oder Segen ?

Naja ich frag mich, warum die cmd.exe die Notwendigkeit dieser Funktion nicht automatisch erkennt und aktiviert.


Grüße
Biber
Biber 26.02.2006 um 18:43:22 Uhr
Goto Top
Danke, yashi,

so macht die gemeinsame Lösungssuche Spaß.. face-wink

verzögerte Variablenauflösung - Fluch, oder Segen ? ^^

Sagen wir so... es ist offensichtlich mit etwas heißer Nadel gestrickt, was die "neue" CMD.exe so alles kann seit W2k..
Vieles ist so grottig schlecht implementiert (die haarsträubendsten Beispiele: Die "Set /a"-Rechenfunktion, die "Maskierung" von Steuerzeichen, das Verhalten von "Echo" beim Aufrufen von Unter-Bätchen, die trailing blanks bei Variablen und eben auch diese DelayedExpansion-Schalter...), dass es sich definitiv nicht "sauber"=im Vertrauen auf die Vollständigkeit der Dokumentation benutzen lässt.
Ich habe neulich grad in meinem (Lieblings-) Batch-Tut III "Datums- und Zeitvariablen" ja wieder mühselig um diese Bugs? Features? herumgecoded.

Dennoch: das Positive überwiegt für mich. Nach meiner Wahrnehmung wurde vor wenigen Jahren von M$ suggeriert, dass jegliche Konsolen-Eingabe im 21. Jahrhundert vollkommen überflüssig/alles antiquierter oder nostalgischer Kram wäre, dem auf Grund der Altersstruktur der mit DOS 2.11 eingestiegenen ITler auch in absehbarer Zeit die Fans wegschmelzen würden...

Seit Win NT/W2K ist gottseidank auch in Redmond die Einsicht da, dass möglicherweise mit Klicki-Bunti nicht alles sinnvoll erledigt werden kann. Und die ganz, ganz lieblosen Beta-Beta-Konsolenutilities, die nach dem Motto "Vollkommen egal, ist eh in drei Jahren alles Geschichte" zusammengeschreddert waren, sind wieder raus aus dem Lieferumfang (ich erinnere an choice.com oder ForFiles.exe).
Dafür sind viele frühere ResKit-Utilities jetzt auf der normalen Anwender-CD dabei. Und ziemlich jedes GUI-Programm hat inzwischen einen /Silent-Schalter bzw. einen Batch-Modus.

Ich finde es also all in all schon gut, dass ein paar "echte Erweiterungen" reingebracht worden - richtig deutlich wird das bei den Fragestellern, die zum Beispiel noch mit Win98 arbeiten und eben mal schnell Tag-Monat-Jahr in einen Log-Filenamen einbauen wollen.. so etwas war schlicht und einfach nicht ohne Verrenkungen möglich vor Win2k.

Und dafür nehme ich gewisse Programmierschwächen bei den Redmondern in Kauf.

Mein Lieblingsbeispiele zum Klarmachen der "DelayedExpansion" ist übrigens auch wieder ein Oneliner-Batch.
::---snipp DelayedDemo.bat -------------
@setlocal EnableDelayedExpansion & @for /l %%i in (1,1,5) do @echo RandomNotDelayed:[%random%] RandomDelayed:[!random!]
::---snipp DelayedDemo.bat -------------

Output:
$cmd$ DelayedDemo.bat
RandomNotDelayed:[2041] RandomDelayed:[13891]
RandomNotDelayed:[2041] RandomDelayed:[5397]
RandomNotDelayed:[2041] RandomDelayed:[6209]
RandomNotDelayed:[2041] RandomDelayed:[22982]
RandomNotDelayed:[2041] RandomDelayed:[30280]

Ich denke, damit wird es dann klar. "Ein Batch sagt mehr als 1000 Worte". *sfg

Und die zweite Frage
Naja ich frag mich, warum die cmd.exe die Notwendigkeit dieser Funktion nicht automatisch erkennt und aktiviert.

Da hatte ich auch mal ein Gegenbeispiel in einem meiner Tutorials... alles zwischen zwei Ausrufungszeichen wird als Variable "aufgelöst", wenn DelayedExpansion aktiv ist. Aus ..
Echo Microsoft! You 're the best - f*ck the rest!
wird in der Anzeige schlicht
Microsoft
Und selbst "einfache Ausrufungszeichen" am Ende einer Fehlermeldung kann ich mit DelayedExpansion nicht einfach anzeigen:
echo Backup failed!
wird zu
Backup failed

Deshalb möchte ich eigentlich gar nicht, dass M$ bzw. die CMD.exe irgendetwas automatisch zu erkennen versucht..*gg

Bis zum nächsten Batch
Frank / der Biber aus Bremen