简体   繁体   English

从python调用需要文件的shell脚本而不将文件写入磁盘

[英]Calling a shell script from python that requires a file without writing the file to disk

For simplification purposes lets assume the shell script is the cat command. 为了简化起见,假设shell脚本是cat命令。 In the shell it would be normally called like this: 在外壳中,通常这样称呼它:

$ cat /some/path/myfile.txt

Now the file will be created dynamically and writing it to disk would be a major performance hit, present security issues and increase the file management overhead in a multiuser environment. 现在,将动态创建文件,并将其写入磁盘将对性能造成重大影响,并带来安全问题,并增加多用户环境中的文件管理开销。 The script cannot be modified nor can read from stdin ( cat was just a working sample). 该脚本不能修改,也不能从stdin中读取( cat只是一个有效的示例)。

I tried this: 我尝试了这个:

import os
pin, pout = os.pipe()
pin, pout = os.fdopen(pin, 'r'), os.fdopen(pout,'w')

from subprocess import Popen
pout.write("test")
pout.flush()
p = Popen('cat /proc/self/fd/%s' % pout.fileno(), shell=True)

Even if I close pout p.poll() still returns nothing showing that the command is still waiting more input from the pipe. 即使我关闭pout p.poll()仍没有返回值显示该命令仍然从管道等待更多的输入。

How can I tell the command there's no more data coming from the pipe? 我怎样才能告诉命令不再有来自管道的数据? Is there any other approach to solve this? 还有其他解决方法吗?

Edit 编辑

In bash, if the file content is generated by a program named prog1 this would be solved in this manner: 在bash中,如果文件内容是由名为prog1的程序生成的,则可以通过以下方式解决:

$ cat <(prog1)

Edit 2 编辑2

If you don't need the shell then the other option mentioned by Alfe is better, though the problem still exists (ie the process is not finishing after reading the file contents) 如果您不需要外壳程序,那么Alfe提到的另一个选项会更好,尽管问题仍然存在(即,在读取文件内容后进程未完成)

#...same as before
p = Popen(['cat', '/dev/stdin'], stdin=pout)

This is what I did at the end but is not nice. 这是我最后做的,但是不好。

Because I'm working on CentOS and the problem I'm having (I've asked about it here: Python Popen can't open bash shell in CentOS/Red Hat ) I can't use execute='/bin/bash' that's why the solution looks a little different than the question. 因为我正在使用CentOS,并且遇到了问题(我在这里问过: Python Popen无法在CentOS / Red Hat中打开bash shell ),所以我不能使用execute='/bin/bash'这就是为什么解决方案看起来与问题有点不同的原因。

What I'm passing in some configuration to the process using bash process substitution and here-documents: 我使用bash流程替换和此处文档将某些配置传递给流程的内容:

file_contents = '...'
p = Popen(['/bin/bash', '-c', "cat <(cat<<'EOF_CFG'\n%s\nEOF_CFG\n)" % file_contents])

I'm now considering using tmpfs for creating named pipes on it. 我现在正在考虑使用tmpfs在其上创建命名管道。 I think that starting the script on it first and then writing to the pipe should work... If I'm successfull I'll write it here too. 我认为应该先在其上启动脚本,然后再将其写入管道中……如果我成功的话,我也将在此处编写它。

Fiddled around a little bit, seems that closing the pipe on the one side does not generate an eof on the associated pseudo file /proc/self/fd/<#> of the child process. 摆弄一点似乎在一侧关闭管道不会在子进程的关联伪文件/ proc / self / fd / <#>上产生eof。 Did you try it with /dev/stdin and simple piping your input to the subprocess's stdin? 您是否使用/ dev / stdin进行了尝试,并将输入内容简单地传递到子进程的stdin?

Try using a named pipe for this. 尝试为此使用命名管道。 On it, EOFs are properly propagated: 在它上面,EOF可以正确传播:

$ mkfifo bla
$ python
from subprocess import Popen
p = Popen('cat bla', shell=True)
with file('bla', 'w') as f:
  f.write('test')

You can create named pipes on the fly from Python as well, of course, just use os.mkfifo() . 当然,也可以使用os.mkfifo()从Python动态创建命名管道。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM