Пакетное перенаправление вывода при использовании команды запуска для приложения с графическим интерфейсом

Это сценарий:

У нас есть скрипт 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, если у вас есть командный файл, который STARTS другой пакетный файл, который STARTs другой пакетный файл (и т. д.), который STARTSa 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" вместо этого делать то, что вам нужно?

Насколько я понимаю, это проблема, и что он хочет сделать:

  1. Не вносите изменений в код Python.
  2. Код Python написан, предполагая, что "temp.txt" больше не используется, когда эта функция возвращает:

    os.system (C: \ batch.bat> C: \ temp.txt 2> & 1)

  3. На самом деле это не так, потому что "batch.bat" порождает интерактивную программу с графическим интерфейсом, используя команду "start".

Как насчет изменения вашего файла "batch.bat", чтобы он содержал:

start c:\the_programm.exe
pause

Это будет держать файл "batch.bat" работающим, пока вы не нажмете клавишу в этом окне. Как только вы нажмете клавишу, вернется команда python "os.system", а затем python вызовет "os.remove".

Другие вопросы по тегам