子进程破坏管道和文件繁忙

时间:2014-10-29 07:52:20

标签: python linux bash shell

我正在尝试使用python做一些文件系统的东西,因为我不想处理复杂的shell脚本,而是宁愿将我的所有编程限制在python中。 shell命令在' search_string'读取目录中的文件名,并将前10个名称写入文件。

search_string = "find " + rootDir + "/"+str(k)  +" -iname \"*\" -type f | head -10  >> negatives" + str(i) + ".txt"
print(search_string)
subprocess.call(search_string, shell=True)

此代码适用于我的ubuntu 14.04 pc,但不适用于最终必须运行的aws,给出错误:

find: `standard output': Broken pipe
find: write error

ubuntu@ip:$ uname -r
3.13.0-37-generic

所以我决定将long shell命令写入一个我认为很容易调用的文件(在使用chmod命令使shell脚本文件可执行后):

search_string = "sudo find " + rootDir + "/"+str(k)  +" -iname \"*\" -type f | head -10  >> trainingfiles/negatives" + str(i) + ".txt"
f=open("cmd.sh","w")
f.write(search_string)
f.flush()
os.fsync(f.fileno())
f.close
p1=subprocess.Popen(["chmod","+x","/home/www-data/web2py/applications/fingerPrint/modules/classifier_stuff/cmd.sh"],stdout=subprocess.PIPE,stderr=subprocess.PIPE)
stdout, stderr = p1.communicate()
output = p1.communicate()[0]
print('stdout:'+stdout+' stderr:'+stderr)
sys.stdout.flush()

p2=subprocess.Popen(["sudo /home/www-data/web2py/applications/fingerPrint/modules/classifier_stuff/cmd.sh"],stdout=subprocess.PIPE,stderr=subprocess.PIPE)
stdout, stderr = p2.communicate()
print('stdout:'+stdout+' stderr:'+stderr)
sys.stdout.flush()

但我得到

stdout: stderr:
Traceback (most recent call last):
File "prepare_and_train.py", line 56, in <module>
 p2=subprocess.Popen(["/home/www-data/web2py/applications/fingerPrint/modules/classifier_stuff/cmd.sh"],stdout=subprocess.PIPE,stderr=subprocess.PIPE)
File "/usr/lib/python2.7/subprocess.py", line 710, in __init__
    errread, errwrite)
File "/usr/lib/python2.7/subprocess.py", line 1327, in _execute_child
    raise child_exception
OSError: [Errno 26] Text file busy

如果我将PIPE改为STDOUT,我会得到一个有趣的

OSError: [Errno 9] Bad file descriptor

和相同的文件忙碌&#39;当我尝试subprocess.call时:

sudo: unable to execute ./cmd.sh: Text file busy
stdout: stderr:

我真的不在乎我是怎么做的,我只想要工作代码 - 这里有任何提示吗?我(很明显)对linux来说是新手

2 个答案:

答案 0 :(得分:2)

您正在进行的错误正在发生,因为您正在尝试执行脚本,同时它仍处于打开状态以进行写入。特别是,请参阅以下最小示例:

#!/usr/bin/env python

import os

f = open('f.sh', 'w')
f.write("#!/bin/sh\necho test")
os.chmod('f.sh', 0o755)
os.execl('f.sh', './f.sh')

如果你执行它,你会得到:

$ ./a.py 
Traceback (most recent call last):
  File "./a.py", line 8, in <module>
    os.execl('f.sh', './f.sh')
  File "/usr/lib64/python3.4/os.py", line 491, in execl
    execv(file, args)
OSError: [Errno 26] Text file busy

如果您确保在执行前关闭文件,例如:

#!/usr/bin/env python

import os

with open('f.sh', 'w') as f:
    f.write("#!/bin/sh\necho test")
os.chmod('f.sh', 0o755)
os.execl('f.sh', './f.sh')

它工作正常:

$ ./a.py 
test

进入您的具体问题,第6行:

f.close

您缺少括号,因此您只需获取(而不是使用)它,而不是调用close()方法。那应该是:

f.close()

或者在我的示例中优先使用with语句。

在此期间,您可能还想使用os.chmod()而不是调用外部chmod工具。

答案 1 :(得分:1)

“破损管道”错误是正常的,并且对于管道为head或类似实用程序的任何内容都是预期的。

稍微分解一下,

  1. 进程一开始写入管道
  2. 处理二开始从管道读取
  3. 处理两个完成并关闭管道
  4. 进程1尝试将更多数据写入管道
  5. 当你没有大量输出时,(4)永远不会发生,所以你不会一直看到这个错误。但这是正常的和预期的。

    无论如何,我会处理Python本身的head部分。然后你也可以取消shell=True

    find = subprocess.Popen(['find', rootDir + '/' + str(k), '-type', 'f'],
        stdout=subprocess.PIPE)
    result = [find.stdout.readline() for x in xrange(10)]
    find.terminate()
    with open('negatives' + str(i) + 'txt', 'w') as output:
        output.write(''.join(result))
    

    -iname "*" find的{​​{1}}参数似乎没有任何用处,所以我把它遗漏了。)

    具有讽刺意味的是,这在Python中比在“复杂”shell脚本中更不透明。当然,在纯Python中,您可以使用os.walk()而不是find