写入错误:断开的管道
我需要在大约300个文件夹上运行一个工具。每次运行大约需要1分钟到30分钟,甚至可能更长时间。所以,我写了一个Python脚本,用循环依次在所有文件夹上运行这个工具。
我的Python脚本大概是这样的:
for directory in directories:
os.popen('runtool_exec ' + directory)
但是当我运行这个Python脚本时,我不断收到以下错误信息:
..
tail: write error: Broken pipe
date: write error: Broken pipe
..
我做的就是通过ssh登录到一个远程服务器,那里放着这个工具、Python脚本和相关的文件夹。当我在命令行中单独运行这个工具,使用的命令是:
runtool_exec directory
这样运行是没问题的。只有在通过Python脚本运行时,才会出现“broken pipe”的错误。
有没有什么想法或者解决办法呢?
2 个回答
如果对其他人有帮助的话,这个问题可能是因为在命令行中使用了管道符号(|)。想要解决这个问题,可以查看这里的方案 https://stackoverflow.com/a/4106633/1904913
你看到的错误是因为你在用 os.popen()
来运行命令,这样会打开一个管道并连接到命令的 stdout
(标准输出)。每当命令(或者它执行的任何东西)想要写入 stdout
时,它就会尝试写入这个管道。但是你没有保存这个管道,因为你没有把 os.popen()
的结果赋值给任何变量,所以 Python 会把它清理掉并关闭。这样,试图写入这个管道的进程就会遇到“管道损坏”的问题,从而产生你看到的错误。(os.popen()
并没有把 stderr
(标准错误)重定向到管道,所以你仍然能看到错误信息。)
另外,你在调用 os.popen()
时没有检查 directory
里是否包含了你 shell 特殊的字符。如果目录里有引号或者星号之类的字符,可能会出现奇怪的情况。像这样使用 os.popen()
是不太好的。
你应该使用 subprocess.Popen()
,并明确告诉它你想如何处理进程的输出(包括标准输出和标准错误)。你需要给 subprocess.Popen()
传递一个参数列表(包括你想要启动的东西),而不是一个单独的字符串,这样就完全避免了使用 shell,省去了检查字符串的麻烦。如果你真的想忽略输出,可以用类似下面的方式:
devnull = open(os.devnull, 'w')
for directory in directories:
subprocess.Popen(['runtool_exec', directory], stdout=devnull)
不过我强烈建议你至少对 subprocess.Popen
的结果做一些基本检查,以确保进程没有提前结束或返回错误代码。