yashi
Goto Top

multiple Instanzen organisieren mit globalen Variablen ?

mit endlocal & set zur parentshell - aber zur unabhängigen batch ??

Hallo.

Ich wollte erst in den Thread "Gültigkeit von Vars..." schreiben, habe dann aber gemerkt, dass mein Problemchen wohl doch zu komplex wird.
Dort habe ich zwar verstanden, wie ich eine Variable der "Parentshell" übergeben kann, würde das aber auch gern bei unabhängigen batchen verwenden. Bzw möchte ich folgendes erreichen... (the whole story: )

Eine batch "launch.bat" die über WinXP mit einer Dateierweiterung (*.dem) verknüpft ist, wird durch den Doppelklick auf so eine .dem Datei aufgerufen. Nach einigen Operationen startet sie eine Anwendung und übergibt ihr die .dem als Parameter:
start app.exe %~nx1
Nun will ich aber mehr als eine .dem markieren und starten. WinXP führt aber leider bei dieser Aktion
start launch.bat %1
start launch.bat %1
start launch.bat %1
aus und nicht
start launch.bat %1 %2 %3

Und nun zum topic:
Meine Idee war, dass die launch.bat beim 1. Start eine globale Variable setzt (damit eine 2. Instanz der launch.bat dort nachgucken kann) und jeder weitere (gleichzeitige) Start der launch.bat nur zur Erzeugung einer globalen Var aus dem Parameter führt. zB so:

if NOT defined apprun (
Endlocal & set "apprun=1"
setlocal
) else (
Endlocal & set "globvar%apprun%=%~nx1"
exit
)
::weiter im Text nur dei der 1. Instanz
::nach ca 2 Sekunden Laufzeit:
start app.exe %~nx1 %globvar1% %globvar2% %globvar3% ...
:face-sadbis max 8 params sollen möglich sein)


Die globvars werden nur übergeben, wenn mehr als eine Datei markiert wurde. Theoretisch. Praktisch funktioniert das mit den globalen Vars nur, wenn sich die launch.bat selber aufgerufen hat. Gibt es also eine Möglichkeit, Vars für eine 2., manuell gestartete batch bekannt zu machen ? Und wenn ja - wie ?
Die Lösung mit einer txt datei als globale var kam mir auch schon in den Sinn; wäre allerdings zu langsam (und außerdem kommt es vor, dass die launch.bat vorzeitig beendet wird und die .txt nicht mehr gelöscht werden kann = Probleme beim nächsten Start)
Letzter Ausweg wäre vielleicht, dass eine weitere Instanz die .txt nur dann zum Speichern ihrer Parameter akzeptiert, wenn sie in den letzten 2 Sekunden erstellt wurde.


Naja ich hoffe ihr habt mich verstanden und könnt helfen
.
mfg, yashi

Content-ID: 28704

Url: https://administrator.de/forum/multiple-instanzen-organisieren-mit-globalen-variablen-28704.html

Ausgedruckt am: 23.12.2024 um 07:12 Uhr

ITwissen
ITwissen 22.03.2006 um 19:55:28 Uhr
Goto Top
Ich glaube ich habe es nicht verstanden, denn ich meine dass du nur folgendes schreiben musst.

start app.exe %1 %2 %3 %4 %5 %6 %7 %8 %9 

Das kanns ja nicht sein, oder?
yashi
yashi 24.03.2006 um 22:42:27 Uhr
Goto Top
Nein. Du hast glaube ich meinen Beitrag nicht richtig gelesen ;)
Denn dann hättest du gesehen, dass diese Zeile sogar vorkommt:

... und nicht
start launch.bat %1 %2 %3


Bzw. eine Batch mit
launch.bat %1 %2 %3
zu starten und in eben diese
app.exe %1 %2 %3
zu schreiben, wäre ja ziemlich überflüssig oder ?
yashi
yashi 28.03.2006 um 11:03:21 Uhr
Goto Top
Scheint wohl nicht lösbar zu sein ?
Keiner eine Idee ?


*zu Biber schiel*
ITwissen
ITwissen 28.03.2006 um 13:52:14 Uhr
Goto Top
Leider muss ich gestehen, dass ich das Problem nicht richtig verstanden habe. Eventuell geht das anderen auch so.

Deine Beschreibung scheint zwar sehr ausfuehrlich, aber irgendwie kommen meine Gedanken nicht nach.

Aber vielleicht habens alle ausser mir verstanden, nur finden sie keine Loesung.
Biber
Biber 30.03.2006 um 21:08:55 Uhr
Goto Top
Hmm, yashi,
ich hatte Deine Frage nicht überlesen... aber da musste ich mir auch Bedenkzeit ausbitten.

Vorläufiges Ergebnis meiner Meditation:

Drei Strategien würden mir einfallen, eine davon geht nicht.

Erste Variante
Was nicht geht, ist das Lesen einen "Globalen Variablen", auf die jede CMD-Instanz zugreufen kann.
Das heißt, Setzen einer "Globalen Variablen" geht zwar mit "SetX.exe", aber... zwei Probleme
- Du kommst von der bereits aktiven Instanz der CMD.exe nie wieder lesend dran.
- Änderungen dieser globalen Variablen gelten nicht für alle aktiven Instanzen.

Simples Beispiel:
Du kannst natürlich auch Variablen wie %cd% (aktuelles Verzeichnis) oder %prompt% in einer von mehreren offenen CMD-Instanzen ändern und auch mit SetX.exe für jede neue Instanz vorgeben, aber:
- eine Änderung der %prompt%s wird ja auch nicht "nachgelesen"/ in allen CMD-Instanzen aktiv
- und keine der Änderungen gilt für CMD.exe's, die Du selber vom CMD-Prompt startest. Da gilt DEIN aktuelles Environment.

...geht nicht, geht nicht, geht nicht... no chance.

Zweite Variante...wie es alle Windows-Programme machen:
Es gibt nur einen Ort im ganzen Windows-Gelumpe, wo Informationen EINmalig und EINdeutig stehen... genau, die Registry.

Das würde funktionieren...aber das wäre mir zu aufwändig und zu dauerhaft.

Dritte Variante
Über eine Datei persistieren.

Das geht relativ sicher
Meiner Meinung nach ist diese Prüfung "nicht älter als zwei Minuten" überflüssig - genau genommen ist diese Prüfung das aufregendste und längste am ganzen Batch.

So würde ein "launch.bat" aussehen können:
::--snipp launch.bat
@echo off
:: Parameter1 [%1] ein *.dem-File
set "demtodo=%temp%\demToDo.lst"  
echo %1>>%demtodo%
ping -n 2 localhost>nul

for /f %%a in (%demtodo%) do call :setAllpara %%a
:: wenn die erste gefundene *.dem-Datei gleich dem Parameter 1 ist..
:: dann hat dieser bat den Job zu tun
IF [%firstdem%]==[%1] (
  del /q %demtodo%
  echo ICH rufe app %allpara%
  :: hier dann: c:\appdir\app.exe %allpara%
  pause
) 
exit

:setallpara
if not defined Firstdem set "Firstdem=%1"  
set allpara=%allpara% %1
goto :eof
:: ---snapp launch.bat
Hier nochmal mit der "Nicht-älter-als-2-Minuten-Prüfung"
::--snipp launch.bat
@echo off & setlocal
:: Parameter1 [%1] ist ein *.dem-File
set "demtodo=%temp%\demToDo.lst"  
If exist %DemTodo%  call :CheckIfOld 
echo %1>>%demToDo%
ping -n 2 localhost>nul
 
for /f %%a in (%demToDo%) do call :setAllpara %%a
:: wenn die erste gefundene *.dem-Datei gleich dem Parameter 1 ist..
:: dann hat dieser bat den Job zu tun
IF [%firstdem%]==[%1] (
  del /q %DemToDo%
  echo ICH rufe app %allpara%
  :: hier dann: c:\appdir\app.exe %allpara%
  pause
) 
exit
 
:setallpara
if not defined Firstdem set "Firstdem=%1"  
set allpara=%allpara% %1
goto :eof
 
:CheckIfOld
 for /f %%a in ('dir /b /s %demtodo%') do (  
 for /f "tokens=2-3 delims=: " %%i in ("%%~ta") do Set /a "FileMins=%%i*60+%%j")  
 for /f "tokens=1-2 delims=:," %%i in ("%time%") do Set /a "TimeMins=%%i*60+%%j"  
 rem Echo filemins: %filemins% timemins: %timemins%
 set /a timediff=%TimeMins%-%FileMins%
 if %timediff% gtr 2 echo %demTodo% ist %timediff% Minuten alt.
 if %timediff% gtr 2 del /q %demTodo%
 pause
 goto :eof
 :: ---snapp launch.bat

Damit würde die von Dir angestrebte Mimik funktionieren (probiers mit Markieren von 3 *.dem-Files im Explorer; vorher Pfade anpassen).

Bin zwar offen für andere Strategien, aber ich wüsste keine andere.
Die Aufgabe an einen Dienst/Service zu delegieren, der zwei, drei Sekunden wartet, bis alle Aufrufe und alle Parameter eingetrudelt sind, wäre IMHO noch aufwändiger.

Grüße
Biber
yashi
yashi 31.03.2006 um 12:54:53 Uhr
Goto Top
Ist schon ok ITwissen ;)
Hab mich vielleicht auch ein bisschen umständlich ausgedrückt. Trozdem Danke für dein Lebenszeichen.

Umso erfreulicher, dass mich der Herr Biber trozdem verstanden hat. Hehe - schön, dass du für mich so ausführlich meditiert hast!
Zum Inhalt:
Den Ausschluß der 1. Variante hatte ich fast befürchtet (aber nicht aufgegeben). Und ob nun Variante 2 oder 3 verwendet wird, kommt bei mir auf's Gleiche heraus: in beiden Fällen wird auf die Festplatte geschrieben = Zeitverlust.
Ich werde mich wohl für die 3. entscheiden müssen. Deshalb noch ein paar Fragen / Gedanken dazu:

1)
muss man innerhalb von subroutinen (:call) nicht trozdem !allpara! verwenden ? dachte DelayedExpansion lässt sich nur mit goto umgehen ?
2)
das mit der "nicht-älter-als-2-SEKUNDEN-Prüfung" hatte ich vorgeschlagen, weil es wie gesagt vorkommen kann, dass die launch.bat nicht bis zur Zeile
del /q %DemToDo%
kommt, sondern vorher vom Benutzer geschlossen wird. Denn die Zeile
ping -n 2 localhost>nul
wird bei mir durch 30-zeiligen Quelltext ersetzt, welcher dann bei der Ausführung mit unerlaubtem Schließen diverser Menüs enden kann. (die launch.bat will zb weitere Parameter abfragen und der Benutzer schließt diese einfach) Das mit den ein bis zwei Sekunden Laufzeit sagte ich deshalb, weil die launch.bat im günstigsten Fall (nämlich dann wenn sie alles findet was sie finden soll) mindestens ein, zwei Sekunden brauch um die Zeile
for /f %%a in (%demToDo%) do call :setAllpara %%a
zu erreichen. (Grund: diverse "find"-cmds)
Wenn nun also die "Leiche" demToDo.lst nicht gelöscht wird, werden bei der nächten Ausführung die neuen Params einfach hinzugefügt.
Nun könnte man sich mit
set "demtodo=%temp%\%timestamp%demToDo.lst"  
nochmehrcode...

del %temp%\*.lst
behelfen.
man akzeptiert die demToDo nur wenn sie jünger als 2 Sekunden ist (gehen wir mal davon aus, dass es kein user schafft, die launch.bat unter 2 sekunden neu zu starten)
[edit: Aufrunden des %timestamp%s auf gerade Sekunden ?? /edit]
Und deshalb -
zu :CheckIfOld :
3)
bei der Funktion hast du geschrieben:
dir /b /s %demtodo%
durchsucht der Param /s nicht alle subdirs ? wozu ist der da ?
Ich habe gelesen, dass der param /t zur Angabe eines Zeitfensters da ist. Könnte man den verwenden ?
4)
Die Zeile mit dem del /q in :CheckIfOld könnte man vielleicht auch durch
echo %1>%demToDo%
ersetzen.
(= neues Anlegen der Datei)


So ich werde erstmal experimentieren. Danke erstmal soweit !
mfg
Biber
Biber 31.03.2006 um 15:17:34 Uhr
Goto Top
Moin yashi,

tja, die Kröte mit dem Zeitverlust wirst Du wohl schlucken müssen..
Es gibt keine Chance, dass Du einen Zähler, den eine "parallele" andere CMD-Instanz von 41 auf 42 hochgesetzt hat, irgendwie auslesen kannst.

Zu Deinen Fragen (danke fürs aufmerksame Lesen):

ad 1)
muss man innerhalb von subroutinen (:call) nicht trozdem !allpara! verwenden ?
dachte DelayedExpansion lässt sich nur mit goto umgehen ?
Nein. "Call :sub"-Routinen sind eigentlich anderen Batchdateien vergleichbar, die mit "Call AndererBatch.bat" aufgerufen werden.
Die "DelayedExpansion" braucht man/frau nur in den Fällen, in denen
  • der CMD-Interpreter einen ganzen (aus Lesbarkeitsgründen mehrzeiligen) Block als eine Zeile einliest
In der Set-Hilfe (Set /?) ist dieses Beispiel
    set VAR=vorher
    if "%VAR%" == "vorher" (  
        set VAR=nachher;
        if "%VAR%" == "nachher" @echo Es funktioniert!  
    )
...bei dem ja NIE "Es funktioniert!" geschrieben wird.
Weil: der CMD löst beim Einlesen der "IF (..)"-Anweisung EINmalig die Variable %VAR% auf.
  • den andere Fall,wo es nötig ist, sind die Variablen-in-Variablen wie
- Ersetze Suchtext in Variable z.B lösche in Username den Domainnamen[ !username:%USERDOMAIN%=! ]
- oder gib mir einen Substring einer Variablen von einer variablen Position an. [ !var:~%pos%! ]
  • oder in dem Fall, das eine frisch gesetzte Variable noch in gleichen Zeile umgeformt werden muss

Die Zeile
for /f %%a in (%demToDo%) do call :setAllpara %%a
ist auch für die CMD.exe EINE Zeile, auch wenn dort ein "Call: blah" aufgerufen wird

Wenn ich irgendetwas unleserliches hätte zusammentrümmern wollen, hätte ich auch mit...
for /f %%a in (%demToDo%) do (
   set allpara=!allpara! %%a
   if not defined FirstDem set FirstDem=%%a
)
...das Ganze in einer (formatierten) Zeile schreiben können - ohne "Call: blah"
Ich fand es mit "call" leserlicher/wartbarer.
Und in eine Zeile bekomm ich es hier im Forum eh nicht... *g

zu 3)
Das "dir /b /s %demtodo%".....ja, erwischt....

Ich habe den (scheinbar überflüssigen) Parameter "/s" genommen, weil...
Microsoft kann noch schlechter programmieren als ich.
(Die Verleumdungslage riskier ich jetzt mal).

Mach mal folgendes (wortwörtlich/nichts anzupassen) am CMD-Prompt:
$cmd$for /f %i in ('dir /b  %temp%\*.tmp') do @echo %~nxi  
(....alle Dateien *.tmp werden mit Namen und Endung aufgelistet)

$cmd$for /f %i in ('dir /b  %temp%\*.tmp') do @echo %~nxi %~ti  
(....alle Dateien *.tmp werden mit Namen und Endung aufgelistet) *stutz -Nanu????

$cmd$for /f %i in ('dir /b /s %temp%\*.tmp') do @echo %~nxi %~ti  
(....alle Dateien *.tmp werden mit Namen, Endung und Änderungsdatum aufgelistet) ?????Nanu????

Na ja, M$ halt... gottseidank werden die wohl nicht die Fußball-WM übertragen...

ad 4)
Die Zeile mit dem del /q in :CheckIfOld könnte man vielleicht auch durch
> echo %1>%demToDo%
> 

Ja. Jein.
echo.>%demToDo%
So würde ich es machen.. noch kürzer. Ich will doch eine leere Datei haben ... nicht eine mit Parameter 1.

Grüße und viel Spaß beim Experimentieren.
Biber
yashi
yashi 01.04.2006 um 23:11:28 Uhr
Goto Top
Hehe -
sieht wohl so aus, als würde es Zeit für das von dir angekündigte DelayedExpansion Tuto ;)
Also das mit den Variablen-in-Variablen ist mir garnicht in den Sinn gekommen ! Naja wieder etwas dazu gelernt...

Woah. Und das mit dem /s -Param setzt der Bug-Liste ja wohl die Krone auf. Einen Bug mit einem anderen Bug (im Quellcode) ausgleichen oder wie ? ^^ Aber das sind wir ja gewöhnt von MS...

So. Danke dir für deine Anregungen & Erklärungen. Ich hab jetzt mein kleines batch für das Öffnen mehrerer files optimieren können. (was die Arbeit der Benutzer sehr vereinfachen wird)
Super, dann markier ich den thread mal als gelöst (zwar auf den befürchteten Umwegen, aber man kann ja nicht alles haben) und sage Tschüss bis zum nächsten Batch !


euer Yashi