Получить значение ERRORLEVEL (или код возврата) из пакета после вызова из Python

Я сделал скрипт (названный isPA64.bat), чтобы определить, является ли работающая система 64-битной (на основе этого Bear's Log совет):

@echo off
setlocal
set str1=%PROCESSOR_ARCHITECTURE%
set/A sixty4=0
if not x%str1:64=%==x%str1% set/A sixty4=1
endlocal & exit/B %sixty4%

Он вызывается из другого простого пакета с именем callpa.bat (его можно было бы вызвать и напрямую, но это доказывает, что ERRORLEVEL действительно устанавливается соответствующим образом):

@echo off
ver>nul & (call isPA64.bat & if ERRORLEVEL 1 (echo 64-bit & exit/B 1) else (echo not 64-bit & exit/B 0))

До этого момента все это работало нормально; однако я должен вызвать один из этих двух из программы Python 3.7.2. Я делаю это:

import subprocess
print(subprocess.run(["callpa.bat"]))

Достаточно просто, не так ли? Но я не смог понять, как вернуть правильный код возврата в коде Python... Есть ли способ назначить переменную в коде Python либо коду «выход»/возврата, либо коду значение ERRORLEVEL из оболочки cmd.exe, которая выполняет сценарий внешнего уровня? ... Я не могу найти способ сделать это в документации по python.


person Rob F.    schedule 02.01.2020    source источник
comment
Вы говорите, что print(subprocess.run(["callpa.bat"])) не показывает вам правильный код возврата или что он показывает, и вы просто не знаете, как получить его программно?   -  person Joseph Sible-Reinstate Monica    schedule 02.01.2020
comment
Почему бы не использовать только один командный файл, callpa.bat, нет необходимости в isPA64: @If %PROCESSOR_ARCHITECTURE:~-2% Equ 86 (If Defined PROCESSOR_ARCHITEW6432 (Exit /B 0)Else Exit /B 1)Else Exit /B 0. Вы также заметите, что я использовал более надежный код, так как 64-битная система, работающая под управлением 32-битного процесса, будет неправильно возвращать x86 без дополнительной проверки.   -  person Compo    schedule 02.01.2020
comment
Вы даже можете обнаружить, что избавление от обоих командных файлов и выполнение аналогичных действий путем непосредственного чтения переменных среды после importing os и чтения os.environ['PROCESSOR_ARCHITECTURE'] и os.environ['PROCESSOR_ARCHITEW6432'] работает на вас.   -  person Compo    schedule 02.01.2020
comment
Почему бы не попробовать определить битность прямо в Python? См. Обнаружение 64-битной ОС (Windows) в Python, а также Как определить, поддерживает ли ОС 16-битные исполняемые файлы в Python?   -  person aschipfl    schedule 02.01.2020
comment
Пробовал rc=subprocess.call(callpa.bat, shell=True) -- пробовал и Shell=False -- но всегда получаю 0 ("echo %ERRORLEVEL%") на 64-битной машине (с 32-битным python --но с моим кодом это не имеет значения); Я должен получить 1, так как это также дает callpa.bat при запуске непосредственно из того же окна командной строки, что и приложение Python. В конечном итоге я планирую использовать один пакетный файл — или даже лучшее решение — однако приложение внешнего уровня поддерживается совместно в пакетной программе и Python, поэтому я надеюсь повторно использовать isPA64.bat (или улучшенный .bat, как у Compo).... для простоты хочу сохранить две одинаковые версии приложения.   -  person Rob F.    schedule 02.01.2020
comment
Значение переменной среды PROCESSOR_ARCHITECTURE зависит от 64-разрядной версии Windows, если к ней обращается 32-разрядное или 64-разрядное приложение. Значение переменной среды равно x86, а не AMD64, как вы, скорее всего, ожидаете, если скрипт Python интерпретируется 32-разрядным python.exe, работающим в 64-разрядной Windows. См. статью Microsoft о Подробности реализации WOW64 . Лучше проверить, определена ли вообще переменная среды ProgramFiles(x86), что имеет место только в 64-битной Windows.   -  person Mofi    schedule 02.01.2020
comment
Затем можно узнать, является ли текущий процесс 32-битным процессом, работающим в 64-битной Windows, проверив, существует ли файл с путем %SystemRoot%\Sysnative\cmd.exe, где SystemRoot также является предопределенной переменной среды, которая содержит путь к каталогу Windows. %SystemRoot%\Sysnative\cmd.exe существует только для 32-битных процессов, работающих в 64-битной Windows, см. статью Microsoft о Перенаправитель файловой системы. Нет необходимости в пакетном файле, чтобы узнать все это из скрипта Python.   -  person Mofi    schedule 02.01.2020
comment
@Joseph Sible-Reinstate Monica Ваш первый комментарий/вопрос затрагивает суть настоящей постоянной проблемы: мой вызов print(subprocess.run(["callpa.bat"])) всегда возвращает 0, даже когда я ожидаю 1. Я интерпретирую результат значение этой функции python неправильно? Нужно ли искать в другом месте, например, в каком-то объекте CalledProcessError? ... Или (маловероятно?) Есть ли ошибка в коде возвращаемого значения функций python subprocess.run() и/или subprocess.call()?   -  person Rob F.    schedule 03.01.2020
comment
Теперь я вижу проблему: первый комментарий Compo выше указывает на проблему. Я не осознавал, что, хотя мой 32-битный Python запускается из той же командной строки, что и необработанный файл is64PA.bat, они будут давать разные результаты, потому что (я думаю) битовый режим, при прямом запуске пакета он будет выполняться в 64-битном режиме. Кажется, я сделал неправильное предположение. ...Спасибо всем за любезное обсуждение и различные решения, некоторые из которых более надежные, чем другие, но все они в той или иной степени полезны.   -  person Rob F.    schedule 03.01.2020
comment
После некоторых [гораздо более простых] экспериментов я вижу, что рекомендация Mofi проверить, определена ли переменная окружения ProgramFiles(x86), является гораздо лучшим способом добиться того, чего я хочу. Он работает на моей 32-битной машине с пакетом xp; он работает на моей 64-битной машине под управлением Win 8.1 с установленным 32-битным python (и, конечно, проверка исходного пакетного файла запускается и работает нормально). Вот моя новая партия isPFx86defined.bat: @if defined ProgramFiles(x86) (echo Programfiles^(x86^) is defined & exit/B 1) else (echo undefined & exit/B 0) Считаю это полным и адекватным решением.   -  person Rob F.    schedule 03.01.2020


Ответы (1)


Нет необходимости создавать другие пакетные файлы:

import os
arch = os.environ['PROCESSOR_ARCHITECTURE']
if arch == 'x86':
    print("x86")
    exit(0)
else:
    print("x64")
    exit(1)

Затем импортируйте его как переменную уровня ошибки.

WMI также можно использовать:

import sys
import win32com.client
wmiservice = win32com.client.dispatch("WbemScripting.SWbemLocator")
swbemservice = wmiservice.ConnectServer(., "root/cimv2")
items = swbemservice.ExecQuery("Select * From Win32_OperatingSystem")
for item in items:
    if item.OSArchitecture == 'x86':
        print("x86")
        exit(0)
    else:
        print("x64")
        exit(1)

Вам необходимо загрузить Python для расширений Windows с http://sourceforge.net/projects/pywin32/files/

person programmer365    schedule 02.01.2020
comment
Я думал, ты сказал, что собираешься сократить такие ответы! Те, где вы берете комментарии других людей и помещаете их в качестве ответов. В любом случае ваш код либо неполный, либо действителен только для python x64, а также неверен/обратно. Причина этого была ясно объяснена в моих комментариях. Вы также должны проверять наличие определенной переменной с именем PROCESSOR_ARCHITEW6432, когда os.environ['PROCESSOR_ARCHITECTURE'] возвращает x86. Конечно, если бы вы знали, что используете python x64, вы бы уже знали, что это система x64, поэтому вы должны предположить, что архитектура python.exe неизвестна. - person Compo; 02.01.2020
comment
Я читал: современный способ, начиная с Python 2.4, использует модуль подпроцесса (а не os), поэтому вместо этого я пытаюсь реализовать что-то вроде subprocess.call()..... но спасибо, потому что я не знал об os.environ, который выглядит как возможное запасное решение. - person Rob F.; 02.01.2020
comment
На самом деле, Mofi (в комментариях к моему исходному сообщению) наткнулся на то, что я действительно хочу: программно установить правильный путь к другой программе, от которой зависит мое приложение, т. Е. Эта программа установлена ​​​​в ... \ Program Files (x86) \. .. или он находится в ...\Program Files\...? (Использование ProgramFiles(x86) тоже кажется хорошим детектором.) ... Все хорошее обсуждение, но мы отвлеклись: мне еще предстоит определить, почему мой python rc=subprocess.call("isPA64.bat") дает неправильный rc в 64-битной системе, работает в режиме 32, когда прямой вызов isPA64.bat из той же командной строки действительно дает правильный rc. - person Rob F.; 03.01.2020
comment
Извините за поздний ответ, Мофи, ваше наблюдение верно на 100%. Это было очень досадное недоразумение. И я не могу проверить это на 64-битном компьютере, так как у меня 32-битный. А Compo я включаю другим способом. Я сохраняю, что копировал ваш комментарий несколько раз, но на этот раз я расширил ваш комментарий и превратил его в полный код. - person programmer365; 03.01.2020