Forum: PC-Programmierung Mit Python das Environment nach Batch-lauf Abfragen?


von cppbert3 (Gast)


Lesenswert?

Gibt es einen eleganten Weg die Environment-Variable die mit einer 
Batch-Datei zusätzlich angelegt/veraendert wurden in python einzulesen?
und stdout und stderr als Strings/Liste zu bekommen?

z.B. diese VS2019 bat-Datei erzeugt ein Build-Environment (VS2008, 
VS2010 usw. legen andere Variable an)
1
%comspec% "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\Common7\Tools\VsDevCmd.bat"

der Aufruf erstellt ca. 40 Environment-Variablen und veraendert den Path 
so damit folgenden Build-Schritte funktionieren

sind recht viele und die sind bei anderen, älteren Studio-Versionen auch 
wieder ganz andere

ich kann die .bat Dateien selbst nicht ändern (sollte man auch niemals)

meine Idee war es am Ende noch eine "set" Aufruf mit Umleitung in eine 
Datei in den %compspec% Aufruf mit ein zu bauen - aber irgenwie
empfinde ich das als unsauber - aber möglicherweise ist das der einzige 
Weg, ich brauche aber auf jeden Fall stdout und stderr noch zusätzlich

ich möchte so weit wie möglich "Datei-Kommunikation" vermeiden, aber mir 
fällt nichts besseres ein als die set-Ausgabe in eine Datei umzuleiten

Links die ich noch dazu gefunden habe:

https://stackoverflow.com/questions/27980567/call-a-bat-file-from-python-and-import-the-environment
https://stackoverflow.com/questions/28271798/script-calling-batch-file-that-sets-environment-variables

in cpython habe ich diesen Code gefunden:

https://hg.python.org/cpython/file/648dcafa7e5f/Lib/distutils/msvc9compiler.py#l263

272ff
1
log.debug("Calling 'vcvarsall.bat %s' (version=%s)", arch, version)
2
popen = subprocess.Popen('"%s" %s & set' % (vcvarsall, arch), stdout=subprocess.PIPE,stderr=subprocess.PIPE)

jemand eine feine Idee oder Tips?

von cppbert3 (Gast)


Lesenswert?

und ganz vergessen: an den Errorlevel von der Batch-Datei muss ich auch 
noch ran :/

hier ein batch-test der alle Daten auspuckt die ich so brauche - ich 
hoffe
mein stdout/stderr schreiben ist so richtig
1
@echo off
2
set neue_var=neuer_wert
3
set path=%path%;neuer_wert
4
echo "stdout" 1> stdout
5
echo "stderr" 2> stderr
6
exit /b 123

geht das mit popen oder muss ich da wirklich noch eine batch-Datei
1
import subprocess
2
p = subprocess.Popen(["ntpq", "-p"], stdout=subprocess.PIPE,stderr=subprocess.PIPE)
3
out, err = p.communicate()

oder macht man das eigentlich völlig anders?

von cppbert3 (Gast)


Lesenswert?

so ist die test.bat wohl richtiger
1
@echo off
2
set neue_var=neuer_wert
3
set path=%path%;neuer_wert
4
echo from stdout
5
echo from stderr 1>&2
6
exit /b 123

von cppbert3 (Gast)


Lesenswert?

damit bekomme ich stdout, stderr und den errorlevel
1
import subprocess
2
3
p = subprocess.Popen(["C:\\temp\\batch_test\\test.bat", "param1"], stdout=subprocess.PIPE,stderr=subprocess.PIPE)
4
try:
5
  stdout, stderr = p.communicate()
6
  
7
  print("stdout: "+str(stdout.decode("utf-8")))
8
  print("stderr: "+str(stderr.decode("utf-8")))
9
  print("returncode: "+str(p.returncode))
10
finally:
11
  p.stdout.close()
12
  p.stderr.close()

bis hier her geht das noch ganz einfach

aber wie mache ich das mit den Environment-Variablen?

von cppbert3 (Gast)


Lesenswert?

hier mein vollständiger Test
1
'''
2
[test.bat]
3
@echo off
4
echo first param: %1
5
set neue_var=neuer_wert
6
set path=%path%;neuer_wert
7
echo from stdout
8
echo from stderr 1>&2
9
exit /b 123
10
'''
11
12
import subprocess
13
import os
14
15
path=os.path.abspath(os.path.dirname(__file__))
16
17
test_bat_path=path+"\\test.bat"
18
error_level_path=path+"\\error_level.txt"
19
env_path=path+"\\env.txt"
20
21
cmd = test_bat_path + " param1 & call echo %errorlevel% > " + error_level_path + " & call set > "+env_path;
22
23
print("cmd: "+cmd)
24
25
p = subprocess.Popen(cmd, stdout=subprocess.PIPE,stderr=subprocess.PIPE)
26
try:
27
  stdout, stderr = p.communicate()
28
  
29
  print("stdout: ["+str(stdout.decode("utf-8"))+"]\n")
30
  print("stderr: ["+str(stderr.decode("utf-8"))+"]\n")
31
  print("returncode: "+str(p.returncode))
32
  
33
  with open(error_level_path, 'r') as reader:
34
    print("error_level.txt: "+str(reader.readlines()));
35
36
  with open(env_path, 'r') as reader:
37
    print("env.txt: "+str(reader.readlines()));
38
39
finally:
40
  p.stdout.close()
41
  p.stderr.close()

der Trick mit dem & und set in Datei umleiten geht, der call muss 
scheinbar sein damit nicht zu früh evaluiert wird, aber komme so nicht 
mehr an den 123 Error-Level dran

von Dirk (Gast)


Lesenswert?

Wieso so umständlich die Environmentvariablen prüfen? Die Werte sind 
doch bekannt oder?

Was spricht gegen die Möglichkeit direkt die Variablen zulesen, wie hier 
beschrieben?

https://able.bio/rhett/how-to-set-and-get-environment-variables-in-python--274rgt5#:~:text=To%20set%20and%20get%20environment%20variables%20in%20Python%20you%20can,Get%20environment%20variables%20USER%20%3D%20os.

von cppbert3 (Gast)


Lesenswert?

Dirk schrieb:
> Wieso so umständlich die Environmentvariablen prüfen? Die Werte sind
> doch bekannt oder?

Nein nicht wirklich, abhängig von Version, Enterprise, Community etc. 
und OS-Sprache etc. sind die anders (zwischen 20-40 Variablen werden 
erzeugt, teilweise verändert)

ich muss hier VS2008 (WinCE builds) bis VS2019 unter Kontrolle halten 
und die liefern jeweils ihre eigene Standard-Batch Datei mit - jede ein 
bisschen anders - mit Batchdateien funktioniert das super aber ich würde 
das gerne nach Python konvertieren

von da gibs libs für (Gast)


Lesenswert?

Inwiefern hilft da der Dict
1
os.environ
nicht weiter?

Oder sollen die .bat selbst ihre Umgebung ausgeben?

von cppbert3 (Gast)


Lesenswert?

da gibs libs für schrieb:
> Inwiefern hilft da der Dictos.environ
> nicht weiter?
>
> Oder sollen die .bat selbst ihre Umgebung ausgeben?

stell dir vor du hast diese Bat-Datei, die du nicht änder darfst
(weil sie von Microsoft kommt) und die legt ca. 20-40 Env-Vars an die du 
für irgendwelche Microsoft-Produkte in folge brauchst - der Inhalt der 
Vars und auch die Vars sind für dich persönlich völlig unrelevant, aber 
Microsoft-Tools brauchen die trotzdem
1
@echo off
2
echo first param: %1
3
set neue_var=neuer_wert
4
set path=%path%;neuer_wert
5
echo from stdout
6
echo from stderr 1>&2
7
exit /b 123

ich brauche den stdout und den stderr
die errorlevel result 123
und das komplette environment das diese Batch erzeugt hat
in Python

stdout, stderr und das environment bekomme ich
nur der errorlevel 123 will nicht erscheinen - wohl wegen
der & Verknüpfung

eigentlich fehlt mir nur noch der errorlevel

oder jemand zeigt mir wie das viel eleganter geht

andere Idee wäre noch eine batch zu haben welche das
alles intern macht und entsprechend Ausgaben hat - problem
ich habe viele Scripte und möchte nicht unbedingt für jedes andere 
Anzahl an Parametern eine weitere batch-Datei schreiben
1
import subprocess
2
import os
3
4
path=os.path.abspath(os.path.dirname(__file__))
5
6
test_bat_path=path+"\\test.bat"
7
error_level_path=path+"\\error_level.txt"
8
env_path=path+"\\env.txt"
9
10
cmd = test_bat_path + " param1 & echo %errorlevel% > " + error_level_path + " & set > "+env_path;
11
12
print("cmd: "+cmd)
13
14
p = subprocess.Popen(cmd, stdout=subprocess.PIPE,stderr=subprocess.PIPE)
15
try:
16
  stdout, stderr = p.communicate()
17
  
18
  print("stdout: ["+str(stdout.decode("utf-8"))+"]\n")
19
  print("stderr: ["+str(stderr.decode("utf-8"))+"]\n")
20
  print("returncode: "+str(p.returncode))
21
  
22
  content = open(error_level_path).read().splitlines()
23
  print("error_level.txt: "+str(content));
24
25
  result_env = {}
26
  content = open(env_path).read().splitlines()
27
  print("env.txt: "+str(content));
28
29
finally:
30
  p.stdout.close()
31
  p.stderr.close()

von Dirk (Gast)


Lesenswert?

Ich würde es ein kleines bisschen anders machen.

1. Alle Env vars einlesen 
https://gist.github.com/bthaman/f7b2b8db006313f73074fe3dcebf0952
2. batch file starten
3. Schritt 1 wieder und dann die beiden Dictionaries vergleichen, dann 
müsstest Du die Unterschiede bekommen, oder?

Hiermit bekomme ich den returncode der bat datei
1
import subprocess
2
import os
3
test_bat = "d:\\test.bat"
4
retcode = subprocess.call(test_bat)
5
print (retcode)

von cppbert3 (Gast)


Lesenswert?

Dirk schrieb:
> Ich würde es ein kleines bisschen anders machen.
>
> Alle Env vars einlesen
> https://gist.github.com/bthaman/f7b2b8db006313f73074fe3dcebf0952
> batch file starten
> Schritt 1 wieder und dann die beiden Dictionaries vergleichen, dann
> müsstest Du die Unterschiede bekommen, oder?

Das filter der geaenderten,neuen mache ich schon, das geht ja einfach 
wenn man das environment hat

>
> Hiermit bekomme ich den returncode der bat datei
> import subprocess
> import os
> test_bat = "d:\\test.bat"
> retcode = subprocess.call(test_bat)
> print (retcode)

So bekomme ich den errorlevel auch - das funktioniert, aber es kommt nur 
0 wenn man den Aufrufe und set kombiniert

Wie schaffst du es das environment abzufragen bevor der cmd zu geht?
Das Environment wird ja nicht global verändert sondern nur für den call 
Aufruf, danach ist das Environment doch genau so wie vorher, oder?

von C. U. (chriull)


Lesenswert?

cppbert3 schrieb:
> Wie schaffst du es das environment abzufragen bevor der cmd zu geht?
> Das Environment wird ja nicht global verändert sondern nur für den call
> Aufruf, danach ist das Environment doch genau so wie vorher, oder?

In https://docs.python.org/3/library/os.html
steht bei os.environ "This mapping is captured the first time the os 
module is imported, typically during Python startup as part of 
processing site.py. Changes to the environment made after this time are 
not reflected in os.environ, except for changes made by modifying 
os.environ directly."

Aber sorry - k.A. wie man os.environ aktualisiert. Wird aber wohl 
irgendwie gehen ;)

von cppbert3 (Gast)


Lesenswert?

Christian U. schrieb:
> cppbert3 schrieb:
>
>> Wie schaffst du es das environment abzufragen bevor der cmd zu geht?
>> Das Environment wird ja nicht global verändert sondern nur für den call
>> Aufruf, danach ist das Environment doch genau so wie vorher, oder?
>
> In https://docs.python.org/3/library/os.html
> steht bei os.environ "This mapping is captured the first time the os
> module is imported, typically during Python startup as part of
> processing site.py. Changes to the environment made after this time are
> not reflected in os.environ, except for changes made by modifying
> os.environ directly."
> Aber sorry - k.A. wie man os.environ aktualisiert. Wird aber wohl
> irgendwie gehen ;)

Wie schon 3 mal gepostet, das environment bekomme ich über umwege genau 
mit den infos die ich brauche, nur der returncode ist dann immer 0

Ich habe kein problem irgendwelche environment variablen kit python zu 
lesen, oder programme auszuführen, nur batchdateien die das environment 
erweitern + der returncode ist nicht ganz so einfach

von Sebastian (Gast)


Lesenswert?

Eine .bat-Datei wird von einem Programm interpretiert. Unter Unix ist 
das eine Shell, unter Windows der Kommandointerpreter (ich glaub 
command.com). Das Programm wird in einem Prozess ausgeführt, der auch 
das Environment beherbergt. Wenn du eine .bat-Datei von Python aus 
ausführen willst musst du einen neuen Prozess anlegen und darin den 
Kommandointerpreter ausführen, der dann die .bat-Datei interpretiert. 
Dieser neue Prozess hat aber ein eigenständiges Environment, das durch 
die .bat-Befehle zwar ergänzt wird, auf dass der Vaterprozess (Python) 
aber keinen Zugriff hat.

Du musst das neue Environment also nach der Ausführung der .bat-Datei 
und vor der Beendigung des Kommandointerpreters irgendwie anders vom 
Kindprozess zum Vaterprozess übertragen.

Da gibt es mehrere Möglichkeiten, aber eine Datei ist mit die 
Einfachste.

LG, Sebastian

von Sebastian (Gast)


Lesenswert?

Wenn der erste Parameter von Popen ein String ist, dann führt Python den 
Kommandointerpreter in dem neuen Prozess aus und übergibt den String als 
Kommandozeile.

In deinem Versuch oben trennst du mehrere Kommando mit &. Die werden 
dann als Hintergrundprozesse gestartet anstatt auf ihre Beendigung zu 
warten. Stattdessen solltest du die Kommandos mit ; trennen. Dann steht 
dir auch der Returncode der Ausführung der .bat-Datei zur Verfügung, der 
ansonsten verfällt.

LG, Sebastian

von cppbert3 (Gast)


Lesenswert?

Sebastian schrieb:
> Eine .bat-Datei wird von einem Programm interpretiert. Unter Unix
> ist das eine Shell, unter Windows der Kommandointerpreter (ich glaub
> command.com). Das Programm wird in einem Prozess ausgeführt, der auch
> das Environment beherbergt. Wenn du eine .bat-Datei von Python aus
> ausführen willst musst du einen neuen Prozess anlegen und darin den
> Kommandointerpreter ausführen, der dann die .bat-Datei interpretiert.
> Dieser neue Prozess hat aber ein eigenständiges Environment, das durch
> die .bat-Befehle zwar ergänzt wird, auf dass der Vaterprozess (Python)
> aber keinen Zugriff hat.
> Du musst das neue Environment also nach der Ausführung der .bat-Datei
> und vor der Beendigung des Kommandointerpreters irgendwie anders vom
> Kindprozess zum Vaterprozess übertragen.
> Da gibt es mehrere Möglichkeiten, aber eine Datei ist mit die
> Einfachste.
> LG, Sebastian

Das ist 100% klar und ich mache es auch mit einer Datei, was auch 
klappt, nur bekomme ich noch nicht den errorlevel aus der bat datei

Mein Code zeigt das doch deutlich oder bin ich da zu ungenau?

von cppbert3 (Gast)


Lesenswert?

Sebastian schrieb:
> Wenn der erste Parameter von Popen ein String ist, dann führt
> Python den Kommandointerpreter in dem neuen Prozess aus und übergibt den
> String als Kommandozeile.
> In deinem Versuch oben trennst du mehrere Kommando mit &. Die werden
> dann als Hintergrundprozesse gestartet anstatt auf ihre Beendigung zu
> warten. Stattdessen solltest du die Kommandos mit ; trennen. Dann steht
> dir auch der Returncode der Ausführung der .bat-Datei zur Verfügung, der
> ansonsten verfällt.
> LG, Sebastian

Werde ich gleich morgen früh testen, Danke

von cppbert3 (Gast)


Lesenswert?

cppbert3 schrieb:
> Sebastian schrieb:
>
>> Wenn der erste Parameter von Popen ein String ist, dann führt
>> Python den Kommandointerpreter in dem neuen Prozess aus und übergibt den
>> String als Kommandozeile.
>> In deinem Versuch oben trennst du mehrere Kommando mit &. Die werden
>> dann als Hintergrundprozesse gestartet anstatt auf ihre Beendigung zu
>> warten. Stattdessen solltest du die Kommandos mit ; trennen. Dann steht
>> dir auch der Returncode der Ausführung der .bat-Datei zur Verfügung, der
>> ansonsten verfällt.
>> LG, Sebastian
>
> Werde ich gleich morgen früh testen, Danke

Ist ; nicht nur für Parametertrennung nutzbar?
Bei der bash ist es ; aber unter Windows Cmd ist Verkettung mit &

von Sebastian (Gast)


Lesenswert?

cppbert3 schrieb:
> Ist ; nicht nur für Parametertrennung nutzbar?
> Bei der bash ist es ; aber unter Windows Cmd ist Verkettung mit &

Mmh, unter Windows rutsche ich etwas. Da sind ja mehrere Ebenen 
involviert, Popen könnte da auch noch mitmischen. Mir kommt es aber so 
vor dass du ganz kurz vor einer Lösung bist ...

LG, Sebastian

von cppbert3 (Gast)


Lesenswert?

Sebastian schrieb:
> Mir kommt es aber so
> vor dass du ganz kurz vor einer Lösung bist ...

nicht wirklich :(

ich hab keine Problem mit Python, Environment-Variablen. Prozessen usw.
nur dieses kleine Detail mit dem Return-Code bei verketteten Aufrufen 
bekomme ich bis jetzt noch nicht hin

von cppbert3 (Gast)


Lesenswert?

ist wohl eher ein Problem mit meinem DOS Batch Verständnis - ich mach da 
mal einen anderen Post für auf - Danke für die Tips

von da gibs libs für (Gast)


Lesenswert?

cppbert3 schrieb:
> Sebastian schrieb:
>> Mir kommt es aber so
>> vor dass du ganz kurz vor einer Lösung bist ...
>
> nicht wirklich :(
>
> ich hab keine Problem mit Python, Environment-Variablen. Prozessen usw.
> nur dieses kleine Detail mit dem Return-Code bei verketteten Aufrufen
> bekomme ich bis jetzt noch nicht hin

Ich deute das wie folgt: popen() bekommt den exitcode vom 
bat-Interpreter (command.com) zurück weil dies sein Kindsprozess ist. 
Wert 0 weil fehlerfrei abgeschlossen.

Der errorlevel der bat (123) bleibt aus Mikrosoftschen Gründen im 
bat-Interpreter hängen... :-(

Resp. Wenn "set" der LETZTE Befehl ist der ERFOLGREICH ausgeführt wird, 
hinterlässt der batt-Interpreter eben DESSEN Exitcode.

Wie muss der bat-Interpreter beendet werden, um einen beliebigen 
errolevel (einer .bat) als eigener exitcode beim beenden zu 
hinterlassen?

von cppbert3 (Gast)


Lesenswert?

da gibs libs für schrieb:
> Resp. Wenn "set" der LETZTE Befehl ist der ERFOLGREICH ausgeführt wird,
> hinterlässt der batt-Interpreter eben DESSEN Exitcode.
>
> Wie muss der bat-Interpreter beendet werden, um einen beliebigen
> errolevel (einer .bat) als eigener exitcode beim beenden zu
> hinterlassen?

ich hab das Problem auch nur auf der Konsole "nachvollziehen" können und 
daraus einen neuen Post gemacht

Beitrag "Win7x64/DOS/CMD-Batch: %errorlevel% kommt "manchmal" richtig raus?"

irgendwie ist das nicht so 100% deterministisch

und in Python mit popen bekomme ich auch diese Effekte - also erst mal 
unter pure CMD verstehen warum das so ist - vielleicht löst sich dann 
mein Python-Problem automatisch mit

von cppbert3 (Gast)


Lesenswert?

da gibs libs für schrieb:
> Resp. Wenn "set" der LETZTE Befehl ist der ERFOLGREICH ausgeführt wird,
> hinterlässt der batt-Interpreter eben DESSEN Exitcode.

das löse ich durch dieses zwischen-echo in eine Datei - und das klappt 
auch "meistens" auf der Konsole -> siehe den anderen Post

von Sebastian W. (wangnick)


Lesenswert?

Ich glaube ich hab eine Lösung.

Angenommen du hast eine Batchdatei test.bat wie folgt:
1
@echo off
2
echo first param: %1
3
set neue_var=neuer_wert
4
set path=%path%;neuer_wert
5
echo from stdout
6
echo from stderr 1>&2
7
exit /b 123

Dann brauchst du noch eine zweite Batchdatei popen.bat:
1
@echo off
2
call %1 %2 %3 %4 %5 %6 %7 %8 %9
3
echo %errorlevel% >ret.txt
4
set >env.txt

Und dann in Python:
1
import subprocess
2
import os
3
path = os.path.abspath(os.path.dirname(__file__))
4
bat = path+"\\popen.bat"
5
ret = path+"\\ret.txt"
6
env = path+"\\env.txt"
7
cmd = bat + " test.bat param1"
8
p = subprocess.Popen(cmd,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
9
try:
10
  stdout, stderr = p.communicate()
11
  print("stdout:\n"+str(stdout.decode("utf-8")))
12
  print("stderr:\n"+str(stderr.decode("utf-8")))
13
  print("ret:\n"+open(ret).read());
14
  print("env:\n"+open(env).read());
15
finally:
16
  p.stdout.close()
17
  p.stderr.close()

LG, Sebastian

von cppbert3 (Gast)


Lesenswert?

Sebastian W. schrieb:
> Ich glaube ich hab eine Lösung.

> Dann brauchst du noch eine zweite Batchdatei popen.bat:@echo off
> call %1 %2 %3 %4 %5 %6 %7 %8 %9
> echo %errorlevel% >ret.txt
> set >env.txt

hatte die Hoffnung auf eine weitere Batch zu verzichten - aber %1 %2 ... 
usw sollte für meine Anforderung (mit 1-5,6 Parameter) auch reichen - 
danke für den Gehirn-Short-Cut damit ich nicht weiter suche

Ich teste das jetzt mal ordentlich

von oerks (Gast)


Lesenswert?

> call %1 %2 %3 %4 %5 %6 %7 %8 %9

Das versagt doch schon bei Leerzeichen in den Parametern oder
mehr als neun Argumenten.

Du solltest dir bessere Ratgeber suchen, die z.B. nicht command.com
fuer die ausfuehrende Interpreterinstanz haelt.
Lustigerweise gibt es fuer WinCE ein command.com.

Wenn man %ERRORLEVER% in einem Script auslesen will, macht man
das ganz einfach so:
1
if errorlevel 255 goto l255
2
if errorlevel 254 goto l254
3
if errorlevel 253 goto l253
4
...
5
if errorlevel 2 goto l2
6
if errorlevel 1 goto l1
7
if errorlevel 0 goto l0
8
echo no match
9
goto ex
10
11
:L255
12
echo 255
13
goto ex
14
:L254
15
echo 254
16
goto ex
17
:L253
18
echo 253
19
goto ex
20
...
21
:L2
22
echo 2
23
goto ex
24
:L1
25
echo 1
26
goto ex
27
:L0
28
echo 0
29
goto ex
30
31
:ex

Werte groesser als 256 gehn halt nicht.
-1 kann ja nicht vorkommen :-).
Obiges Skript ist im uebrigen bei mir 30 Jahre alt.

In einem meiner letzen Projekte musste ich einer anderen Abteilung
2 Skipte zuarbeiten. Wenn ich da nach "Python" oder "Shell" verlangt
haette, waere das ganze genau an der Stelle gestorben.
Da wurde kraeftig mit BACKQUOTE und Quoting gearbeitet.
Solange das bei dir nicht traumhaft sicher sitzt, vergiss das ganze.

Denk mal drueber nach!

von cppbert3 (Gast)


Lesenswert?

oerks schrieb:
> Das versagt doch schon bei Leerzeichen in den Parametern oder
> mehr als neun Argumenten.

dann würde ich in dem Fall das "call %1 %2 %3..."-Script in Python 
generieren - mehr als trivial und  dann habe ich keine Probleme mit 
Parameter-Anzahl und Quoting

oerks schrieb:
> Du solltest dir bessere Ratgeber suchen, die z.B. nicht command.com
> fuer die ausfuehrende Interpreterinstanz haelt.
> Lustigerweise gibt es fuer WinCE ein command.com.

die Microsoft-Tools die ich verwenden muss interessieren sich nicht 
dafür was ich für sinnvoll halte :)

oerks schrieb:
> Wenn man %ERRORLEVER% in einem Script auslesen will, macht man
> das ganz einfach so:

das ist absolut klar - seit mind. 25 Jahren :) - es geht nur darum ein 
paar Batch-Scripte in einen viel größeren Python-Code Verbund zu 
integrieren

oerks schrieb:
> Da wurde kraeftig mit BACKQUOTE und Quoting gearbeitet.
> Solange das bei dir nicht traumhaft sicher sitzt, vergiss das ganze.
>
> Denk mal drueber nach!

keine Ahnung was du mir sagen willst - sind nicht meine Batch-Dateien 
sondern von Microsoft, ich mag kein CMD-Batch wegen dem ganzen Quoting 
Chaos und der eingeschränkten Funktionalität (verglichen mit Python, 
Powershell, selbst Bash ist besser), ist nicht portable, hier gibt es 
einen Haufen Python-Code wo die Batch-Dateien nur stören, je weniger 
Batch umso besser

von Nur_ein_Typ (Gast)


Lesenswert?

cppbert3 schrieb:
> path=os.path.abspath(os.path.dirname(_file_))
>
> test_bat_path=path+"\\test.bat"
> error_level_path=path+"\\error_level.txt"
> env_path=path+"\\env.txt"
>
> cmd = test_bat_path + " param1 & echo %errorlevel% > " +
> error_level_path + " & set > "+env_path;
>
> print("cmd: "+cmd)
>
> p = subprocess.Popen(cmd, stdout=subprocess.PIPE,stderr=subprocess.PIPE)

Statt "+" zur Konkatenation Deiner Pfade solltest Du die Pfadtrenner 
lieber weglassen und die Funktion os.path.join benutzen. Also statt 
'test_bat_path=path+"\\test.bat"' lieber
1
test_bat_path = os.path.join(path, "test.bat")

Wenn Deine Python-Umgebung aktuell genug ist, kannst Du auch die Klasse 
Path aus dem Standardmodul pathlib verwenden. Instanzen dieser Klasse 
kannst Du einfach mit "+" konkatenieren, das kümmert sich automatisch um 
den korrekten Pfadtrenner.

Weiterhin weiß ich ja nicht, wie das in Microsofts cmd.exe oder 
Powershell ist, aber mit dem "&" würdest Du den Prozeß in UNIXoiden 
Systemen sofort in den Hintergrund schicken. Das heißt, Deine "test.bat" 
würde im Hintergrund laufen und noch gar kein Ergebnis (und keine 
Umgebungsvariable "errorlevel" gesetzt haben), wenn Du Dein "echo 
%errorlevel%" aufrufst. Dasselbe gilt für Dein "call set".

Allerdings brauchst Du den ganzen Zinnober über temporäre Dateien nicht, 
wenn ich das richtig sehe. Du kannst das gesamte Environment als 
Dictionary von str() in os.environ oder als Dictionary von bates() in 
os.environb finden, und auch mit os.environ.get('errorlevel') die 
Umgebungsvariable "%errorlevel%" lesen.

von cppbert3 (Gast)


Lesenswert?

Nur_ein_Typ schrieb:
> Weiterhin weiß ich ja nicht, wie das in Microsofts cmd.exe oder
> Powershell ist, aber mit dem "&" würdest Du den Prozeß in UNIXoiden
> Systemen sofort in den Hintergrund schicken. Das heißt, Deine "test.bat"
> würde im Hintergrund laufen und noch gar kein Ergebnis (und keine
> Umgebungsvariable "errorlevel" gesetzt haben), wenn Du Dein "echo
> %errorlevel%" aufrufst. Dasselbe gilt für Dein "call set".

du bist der 2. der das hier schreibt - unter windows cmd ist & das ; in 
bash

Nur_ein_Typ schrieb:
> Allerdings brauchst Du den ganzen Zinnober über temporäre Dateien nicht,
> wenn ich das richtig sehe. Du kannst das gesamte Environment als
> Dictionary von str() in os.environ oder als Dictionary von bates() in
> os.environb finden, und auch mit os.environ.get('errorlevel') die
> Umgebungsvariable "%errorlevel%" lesen.

das Environemnt wird von der ausgeführt Batch-Datei erst erzeugt - 
dieses Environment will ich - das kann man nicht davor und auch nicht 
danach einfach so abfragen - auch nicht unter linux - das Environment 
gilt nur zum Ausführungszeitpunkt des cmd, und der error-level wird erst 
in den callenden Process eingefügt - an den komme ich hier aber auch 
nicht

d.h. deine Tips funktionieren einfach nicht

von cppbert3 (Gast)


Lesenswert?

Nur_ein_Typ schrieb:
> Statt "+" zur Konkatenation Deiner Pfade solltest Du die Pfadtrenner
> lieber weglassen und die Funktion os.path.join benutzen. Also statt
> 'test_bat_path=path+"\\test.bat"' lieber
> test_bat_path = os.path.join(path, "test.bat")

das mache ich normalerweise schon - ich wollte mein Beispiel nur 
"einfach" halten

von Nur_ein_Typ (Gast)


Lesenswert?

Christian U. schrieb:
> In https://docs.python.org/3/library/os.html
> steht bei os.environ "This mapping is captured the first time the os
> module is imported, typically during Python startup

Oh, stimmt, das hatte ich ganz vergessen... :-(

von cppbert3 (Gast)


Lesenswert?

Nur_ein_Typ schrieb:
> Christian U. schrieb:
>> In https://docs.python.org/3/library/os.html
>> steht bei os.environ "This mapping is captured the first time the os
>> module is imported, typically during Python startup
>
> Oh, stimmt, das hatte ich ganz vergessen... :-(

gibt es einen weg das wirklich aktuelle komplette Environment in Python 
zu lesen - am besten als Dict?

von cppbert3 (Gast)


Lesenswert?

oerks schrieb:
>> call %1 %2 %3 %4 %5 %6 %7 %8 %9
>
> Das versagt doch schon bei Leerzeichen in den Parametern oder

aber einfaches Quoting würde es doch auch schon lösen

call "%1" "%2" "%3" "%4" "%5" "%6" "%7" "%8" "%9"...

oder meinst du was wilderes?

> mehr als neun Argumenten.

dann mache ich 64 dann reicht es mir bis 2031

diese call-datei gibt es ja nur 1 mal - who-cares wie lang die wird :)

von da gibs libs für (Gast)


Lesenswert?

> Beitrag "Win7x64/DOS/CMD-Batch: %errorlevel% kommt "manchmal" richtig raus?"
>
> irgendwie ist das nicht so 100% deterministisch
>
> und in Python mit popen bekomme ich auch diese Effekte - also erst mal
> unter pure CMD verstehen warum das so ist - vielleicht löst sich dann
> mein Python-Problem automatisch mit

Tja, der dort angefügte Link https://ss64.com/nt/errorlevel.html 
beschreibt ja unter Qellenangabe "MSFT" die "Mikrosoftschen Gründe":

Inconsistent  Not consistent  do vary / .bat != .cmd / ERRORLEVEL != 
%ERRORLEVEL% != ExitCode / vary by applied ServicePacks

Lösungsleitsatz: "Viel Glück, Du wirst es LEIDER brauchen..."

von cppbert3 (Gast)


Lesenswert?

da gibs libs für schrieb:
> Lösungsleitsatz: "Viel Glück, Du wirst es LEIDER brauchen..."

Sebastians Lösung mit der wrapper bat funktioniert (auch wenn ich dis 
Hoffnung hatte auf eine zusätzliche bat Datei verzichten zu können) 
besser als alles andere was ich probiert habe

Ich generiere jetzt diesen call wrapper direkt in Python und umgehe 
damit alle Probleme (Quoting, Parameteranzahl, Abgreifen Errorlevel, und 
des gesetztes Environments) und es läuft super, jetzt kann ich einen 
Haufe alt Batches die mit allen Tricks if,for,awk,... arbeiten anfangen 
durch trivialen Python code zu ersetzen :)

von cppbert3 (Gast)


Lesenswert?

da gibs libs für schrieb:
> Tja, der dort angefügte Link https://ss64.com/nt/errorlevel.html
> beschreibt ja unter Qellenangabe "MSFT" die "Mikrosoftschen Gründe":
> Inconsistent  Not consistent  do vary / .bat != .cmd / ERRORLEVEL !=
> %ERRORLEVEL% != ExitCode / vary by applied ServicePacks

Das erklärt vieles, Danke

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.