这是情景:
我们有一个Python脚本可以启动Windows批处理文件并将其输出重定向到文件。之后它会读取文件,然后尝试删除它:
os.system(C:\batch.bat >C:\temp.txt 2>&1)
os.remove(C:\temp.txt)
在batch.bat中,我们启动一个这样的Windows GUI程序:
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命令启动程序?
答案 0 :(得分:2)
这有点hacky,但你可以尝试一下。它使用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小时,但我没有任何证据。AT
命令将安排在1天后运行。您可以使用AT {job} /delete
手动恢复,并将x=70
增加到更可接受的范围。遗憾的是,START
命令即使在/i
被忽略当前环境时,也似乎传递了父cmd.exe
进程的打开文件描述符。这些文件描述符似乎被移交给子进程,即使子进程被重定向到NUL,并且即使中间shell进程终止也保持打开状态。如果您有一个批处理文件START
另一个批处理文件START
另一个批处理文件(等)START
是一个GUI Windows应用程序,您可以在Process Explorer中看到这个。一旦中间批处理文件终止,GUI应用程序将拥有文件句柄,即使它(和中间批处理文件)都被重定向到NUL
。
答案 1 :(得分:0)
我认为Windows不允许您删除打开的文件。听起来你想丢掉程序的输出;将重定向到'nul'而不是做你需要的东西?
答案 2 :(得分:0)
据我所知,这是问题,他想做什么:
编写Python代码时假设在此函数返回时不再使用“temp.txt”:
os.system(C:\ batch.bat> C:\ temp.txt 2>& 1)
事实并非如此,因为“batch.bat”使用“start”命令生成交互式GUI程序。
如何更改“batch.bat”文件以包含:
start c:\the_programm.exe
pause
这将使“batch.bat”文件保持运行,直到您点击该窗口上的某个键。一旦你按下一个键,“os.system”python命令将返回,然后python将调用“os.remove”。
答案 3 :(得分:0)
您在阅读完文件后是否正在关闭该文件?以下是我的最终作品:
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()
行,则会失败。
答案 4 :(得分:0)
如果您只是立即删除文件,为什么要捕获到文件?
这个怎么样:
os.system(C:\batch.bat >nul 2>&1)
编辑:哎呀,我错过了关于阅读文件的评论,我只注意到了代码。
答案 5 :(得分:0)
最后,我找到了一个合适的解决方案:
我不再使用批处理文件来启动the_programm.exe,而是使用Python脚本:
from subprocess import Popen
if __name__ == '__main__':
Popen('C:/the_programm.exe', close_fds=True)
close_fds参数将文件句柄与.exe进程分离!就是这样!