Пакетное перенаправление вывода при использовании команды запуска для приложения с графическим интерфейсом
Это сценарий:
У нас есть скрипт Python, который запускает пакетный файл Windows и перенаправляет его вывод в файл. После этого он читает файл, а затем пытается удалить его:
os.system(C:\batch.bat >C:\temp.txt 2>&1)
os.remove(C:\temp.txt)
В batch.bat мы запускаем программу с графическим интерфейсом Windows следующим образом:
start c:\the_programm.exe
Вот и все в партии.
Теперь os.remove() завершается с ошибкой "Отказано в доступе", потому что файл temp.txt все еще заблокирован системой. Кажется, это вызвано тем, что все еще запущен the_programm.exe (чей вывод также, кажется, перенаправлен в temp.txt).
Любая идея, как запустить the_programm.exe без блокировки temp.txt, пока он еще работает? Часть Python вряд ли может быть изменена, так как это инструмент ( BusyB).
На самом деле мне не нужен вывод the_programm.exe, поэтому суть вопроса такова: как мне отделить the_programm.exe от блокировки temp.txt для его вывода? Или: Как использовать START или другую команду Windows для запуска программы без наследования перенаправления пакетного вывода?
6 ответов
Наконец я смог найти правильное решение:
Я больше не использую командный файл для запуска the_programm.exe, но сценарий Python:
from subprocess import Popen
if __name__ == '__main__':
Popen('C:/the_programm.exe', close_fds=True)
Параметр close_fds отделяет дескрипторы файлов от процесса.exe! Это оно!
Это немного глупо, но вы можете попробовать это. Он использует AT
команда для запуска the_programm.exe
до минуты в будущем (которую он вычисляет, используя %TIME%
переменная окружения и SET
арифметическое).
batch.bat:
@echo off
setlocal
:: store the current time so it does not change while parsing
set t=%time%
:: parse hour, minute, second
set h=%t:~0,2%
set m=%t:~3,2%
set s=%t:~6,2%
:: reduce strings to simple integers
if "%h:~0,1%"==" " set h=%h:~1%
if "%m:~0,1%"=="0" set m=%m:~1%
if "%s:~0,1%"=="0" set s=%s:~1%
:: choose number of seconds in the future; granularity for AT is one
:: minute, plus we need a few extra seconds for this script to run
set x=70
:: calculate hour and minute to run the program
set /a x=s + x
set /a s="x %% 60"
set /a x=m + x / 60
set /a m="x %% 60"
set /a h=h + x / 60
set /a h="h %% 24"
:: schedule the program to run
at %h%:%m% c:\the_programm.exe
Вы можете посмотреть на AT /?
а также SET /?
чтобы увидеть, что делает каждый из них. Я остановился /interactive
параметр AT
так как вы прокомментировали, что "никакое взаимодействие с пользователем не допускается".
Предостережения:
- Похоже, что
%TIME%
всегда 24 часа, независимо от языковых настроек на панели управления, но у меня нет никаких доказательств этого. - Если ваша система загружена и batch.bat запускается более 10 секунд,
AT
Команда будет запущена через 1 день. Вы можете восстановить это вручную, используяAT {job} /delete
и увеличитьx=70
к чему-то более приемлемому.
START
Команда, к сожалению, даже когда дано /i
чтобы игнорировать текущую среду, кажется, передать дескрипторы открытого файла родительского cmd.exe
процесс. Эти файловые дескрипторы, похоже, передаются подпроцессам, даже если подпроцессы перенаправляются в NUL, и остаются открытыми, даже если промежуточные процессы оболочки завершаются. Вы можете увидеть это в Process Explorer, если у вас есть командный файл, который START
S другой пакетный файл, который START
s другой пакетный файл (и т. д.), который START
Sa GUI приложение для Windows. После завершения работы с промежуточными пакетными файлами приложение GUI будет владеть файловыми дескрипторами, даже если все они (и промежуточные пакетные файлы) были перенаправлены на NUL
,
Зачем захватывать в файл, если вы просто удаляете его немедленно?
Как насчет этого:
os.system(C:\batch.bat >nul 2>&1)
РЕДАКТИРОВАТЬ: Ой, я пропустил ваш комментарий о чтении файла, я только заметил код.
Вы закрываете файл после того, как прочитаете его? Следующие работы на моем конце:
import os
os.system('runbat.bat > runbat.log 2>&1')
f = open('runbat.log')
print f.read()
f.close()
os.remove('runbat.log')
но не удастся, если я удалю f.close()
линия.
Я не думаю, что Windows позволит вам удалить открытый файл. Похоже, вы хотите выбросить вывод программы; будет ли перенаправление на "nul" вместо этого делать то, что вам нужно?
Насколько я понимаю, это проблема, и что он хочет сделать:
- Не вносите изменений в код Python.
Код Python написан, предполагая, что "temp.txt" больше не используется, когда эта функция возвращает:
os.system (C: \ batch.bat> C: \ temp.txt 2> & 1)
На самом деле это не так, потому что "batch.bat" порождает интерактивную программу с графическим интерфейсом, используя команду "start".
Как насчет изменения вашего файла "batch.bat", чтобы он содержал:
start c:\the_programm.exe
pause
Это будет держать файл "batch.bat" работающим, пока вы не нажмете клавишу в этом окне. Как только вы нажмете клавишу, вернется команда python "os.system", а затем python вызовет "os.remove".