【问题标题】:os.system() vs. os.popen() when using bash process substitution: ls: cannot access '/dev/fd/63': No such file or directoryos.system() 与 os.popen() 使用 bash 进程替换时:ls: cannot access '/dev/fd/63': No such file or directory
【发布时间】:2021-04-15 10:48:05
【问题描述】:

我正在尝试使用os.popen() 编写一个接受文件参数并将其发送到子进程的 Python 程序。它适用于普通文件。但是在使用 bash Process Substitution (short article) 时它不起作用。

为什么os.system() 可以工作,但os.popen() 对于相同的命令会失败(在 Ubuntu 上)?这里是run.py

#!/usr/bin/env python3
import os
import sys

cmd = "ls -l %s" % sys.argv[1]
os.system(cmd)
pipe = os.popen(cmd)
print(pipe.read(), end="")

输出:

# Both os.system("ls -l file") and os.popen("ls -l file") work great
$ run.py file
-rw-r--r-- 1 peter peter 313080 Apr 15 12:27 file
-rw-r--r-- 1 peter peter 313080 Apr 15 12:27 file

# os.system("ls -l /proc/self/fd/11") works great but os.popen("ls -l /proc/self/fd/11") fails
$ run.py <(cat file)
lr-x------ 1 peter peter 64 Apr 15 12:27 /proc/self/fd/11 -> 'pipe:[171197]'
ls: cannot access '/proc/self/fd/11': No such file or directory

有人知道为什么os.popen("ls -l /proc/self/fd/11") 会这样失败吗?

我创建了一个 Perl 版本,perl-run.pl,与上面的 Python run.pl 版本相似,并且 Perl 的 system()open() 都可以正常工作:

#!/usr/bin/perl -w
use strict;

my $cmd = "ls -l $ARGV[0]";
system($cmd);
open(my $i, $cmd . " |");
print <$i>;

输出:

$ perl-run.pl <(cat file) 
lr-x------ 1 peter peter 64 Apr 15 12:27 /proc/self/fd/11 -> 'pipe:[165704]'
lr-x------ 1 peter peter 64 Apr 15 12:27 /proc/self/fd/11 -> pipe:[165704]

【问题讨论】:

    标签: python


    【解决方案1】:

    os.popen 方法实际上只是subprocess.Popen 的包装器。如果我们查看subprocess.Popen 的文档,我们会发现:

    如果 close_fds 为真,则在子进程执行之前,将关闭除 0、1 和 2 之外的所有文件描述符。否则当 close_fds 为 false 时,文件描述符遵循其可继承标志,如文件描述符的继承中所述。

    这意味着当使用像 &lt;(some command) 这样的 shell 结构时,与该重定向关联的文件描述符在执行子进程之前会被关闭,因此相应的 /dev/fd/nn 文件会消失。

    在调用os.popen时无法控制这个标志,但是你可以直接使用subprocess模块,并编写如下内容:

    #!/usr/bin/env python3
    import os
    import subprocess
    import sys
    
    cmd = "ls -l %s" % sys.argv[1]
    os.system(cmd)
    pipe = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, close_fds=False)
    stdout, stderr = pipe.communicate()
    print(stdout, end="")
    

    请参阅subprocess 文档了解与 Popen 对象。

    【讨论】:

      猜你喜欢
      • 2023-04-03
      • 1970-01-01
      • 1970-01-01
      • 2016-09-03
      • 1970-01-01
      • 2020-11-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多