Reindirizzamento dell'output batch quando si utilizza il comando start per l'app GUI
-
13-09-2019 - |
Domanda
Questo è lo scenario:
Abbiamo uno script Python che avvia un file batch di Windows e reindirizza il suo output su un file.Successivamente legge il file e poi tenta di eliminarlo:
os.system(C:\batch.bat >C:\temp.txt 2>&1)
os.remove(C:\temp.txt)
Nel batch.bat avviamo un programma GUI di Windows come questo:
start c:\the_programm.exe
Questo è tutto nel file batch.
Ora os.remove() fallisce con "Autorizzazione negata" perché temp.txt è ancora bloccato dal sistema.Sembra che ciò sia causato dal the_programm.exe ancora in esecuzione (il cui output sembra essere reindirizzato a temp.txt).
Qualche idea su come avviare the_programm.exe senza che temp.txt sia bloccato mentre è ancora in esecuzione?La parte Python è difficilmente modificabile poiché si tratta di uno strumento (Occupato B).
In effetti non ho bisogno dell'output di the_programm.exe, quindi l'essenza della domanda è: Come disaccoppiare the_programm.exe dal blocco di temp.txt per il suo output?O: Come posso utilizzare START o un altro comando Windows per avviare un programma senza ereditare il reindirizzamento dell'output batch?
Soluzione 6
Finalmente ho potuto trovare una soluzione adeguata:
Non sto più utilizzando un file batch per avviare the_programm.exe, ma uno script Python:
from subprocess import Popen
if __name__ == '__main__':
Popen('C:/the_programm.exe', close_fds=True)
Il parametro close_fds disaccoppia gli handle di file dal processo .exe!Questo è tutto!
Altri suggerimenti
Questo è un po' complicato, ma potresti provarlo.Utilizza il AT
comando per eseguire the_programm.exe
fino a un minuto nel futuro (che calcola utilizzando il file %TIME%
variabile d'ambiente e SET
aritmetica).
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
Puoi guardare il AT /?
E SET /?
per vedere cosa sta facendo ciascuno di questi.Ho lasciato fuori il /interactive
parametro di AT
dal momento che hai commentato che "non è consentita alcuna interazione con l'utente".
Avvertenze:
- Sembra che
%TIME%
è sempre di 24 ore, indipendentemente dalle impostazioni locali nel pannello di controllo, ma non ho alcuna prova di ciò. - Se il tuo sistema è carico e batch.bat impiega più di 10 secondi per essere eseguito, il file
AT
l'esecuzione del comando verrà pianificata 1 giorno dopo.Puoi recuperarlo manualmente, utilizzandoAT {job} /delete
, e aumentare ilx=70
a qualcosa di più accettabile.
IL START
comando, purtroppo, anche quando dato /i
per ignorare l'ambiente corrente, sembra trasmettere i descrittori di file aperti del genitore cmd.exe
processi.Questi descrittori di file sembrano essere trasferiti ai sottoprocessi, anche se i sottoprocessi vengono reindirizzati a NUL, e vengono mantenuti aperti anche se i processi di shell intermedi terminano.Puoi vederlo in Esplora processi se hai un file batch che START
c'è un altro file batch che START
s un altro file batch (ecc.) che START
È un'app Windows GUI.Una volta terminati i file batch intermedi, l'app GUI sarà proprietaria degli handle di file, anche se (e i file batch intermedi) sono stati tutti reindirizzati a NUL
.
Non penso che Windows ti permetterà di eliminare un file aperto.Sembra che tu voglia buttare via l'output del programma;il reindirizzamento a "nul" farebbe invece ciò di cui hai bisogno?
A quanto ho capito, questo è il problema e cosa vuole fare:
- Fare NO modifiche al codice Python.
Il codice Python viene scritto presupponendo che "temp.txt" non venga più utilizzato quando questa funzione restituisce:
os.system(C:\batch.bat >C: emp.txt 2>&1)
In realtà questo non è il caso perché "batch.bat" genera un programma GUI interattivo utilizzando il comando "start".
Che ne dici di cambiare il tuo file "batch.bat" per contenere:
start c:\the_programm.exe
pause
Ciò manterrà il file "batch.bat" in esecuzione finché non premi un tasto in quella finestra.Una volta premuto un tasto, verrà restituito il comando python "os.system", quindi python chiamerà "os.remove".
Stai chiudendo il file dopo aver finito di leggerlo?I seguenti lavori alla mia fine:
import os
os.system('runbat.bat > runbat.log 2>&1')
f = open('runbat.log')
print f.read()
f.close()
os.remove('runbat.log')
ma fallisce se rimuovo il file f.close()
linea.
Perché acquisire in un file se lo elimini immediatamente?
Cosa ne pensi di questo:
os.system(C:\batch.bat >nul 2>&1)
MODIFICARE:Ops, mi ero perso il tuo commento sulla lettura del file, ho notato solo il codice.