【问题标题】:Python subprocess call is not workingPython子进程调用不起作用
【发布时间】:2014-10-14 11:49:50
【问题描述】:

我正在编写一个 Python 程序,我需要执行这个相当长的 shell 命令并在我的脚本中接收输出。

test = subprocess.Popen(shlex.split("find /home/disk1 -maxdepth 0 -name folder1* -o -name folder7*"), stdout=subprocess.PIPE, shell=True) 
test.communicate()

我已经尝试了所有可能的代码变体,比如在参数中添加 'executable="/bin/bash",或者使用 subprocess.check_output 等。

每当我运行它并通过键入“test.communicate()”检查输出时,我都会得到“/home/disk1”目录中的所有文件,而不是我根据命令想要的文件。当我在 shell 中键入这个 find search 时,它工作正常。我不知道为什么它不起作用。我在互联网上浪费了最后两个小时。我在这里很困惑,请帮助我。

编辑:根据 cmets,我还尝试从参数中省略 'shell=True',这种情况下的响应是: (b'', None) 我期待使用此命令的 4 个文件的名称。这还是不对的。谢谢。

编辑:对不起,我不是在寻找文件,我在寻找文件夹。

【问题讨论】:

  • 你不需要shell=True
  • ...作为一般规则,不仅仅是“不需要”,而是“不应该使用”。 shell=True 被认为是有害的,完全违背了使用 shlex.split() 的目的。
  • ...顺便说一句,您应该使用 -print0 参数来查找以 NUL 分隔其输出,并使用 .split('\0') 将其划分 - 否则,包含换行符的文件名(其中,是的,完全合法)会搞砸你。当然,这是假设您没有做正确的事情,而是使用os.walk()
  • 你甚至不需要 fork 一个孩子就可以在这里运行find。只需使用glob.glob('/home/disk1/file[17]*') 即可获取匹配文件名列表。

标签: python linux bash shell subprocess


【解决方案1】:
  1. 命令

    find /home/disk1 -maxdepth 0 -name file1* -o -name file7*
    

    不会产生任何输出。深度 0 处的唯一对象是 /home/disk1,其名称与任何一个表达式都不匹配。所以运行该命令的预期结果是空的。你可能想要-maxdepth 1。但是,如果您不需要递归搜索,find 就大材小用了;您可以对模式进行全局扩展。

  2. 当您在subprocess.Popen 的构造函数中指定shell=True 时,您应该传递一个包含整个命令的字符串,然后将其传递给shell。您可以通过提供单个字符串参数或具有一个元素的列表来执行此操作,该元素是字符串。对于shell=False,您需要提供一个列表,其第一个元素是要运行的程序,其余元素是参数。因此,以下任何一项都会产生预期的结果:

    test = subprocess.Popen(
             "find /home/disk1 -maxdepth 1 -name file1* -o -name file7*"
             , stdout=subprocess.PIPE, shell=True) 
    test = subprocess.Popen(
             ["find /home/disk1 -maxdepth 1 -name file1* -o -name file7*"]
             , stdout=subprocess.PIPE, shell=True) 
    test = subprocess.Popen(
             shlex.split(
                 "find /home/disk1 -maxdepth 1 -name file1* -o -name file7*")
             , stdout=subprocess.PIPE) 
    test = subprocess.Popen(["find", "/home/disk1"
                                   , "-maxdepth", "1"
                                   , "-name", "file1*"
                                   , "-o"
                                   , "-name", "file7*"]
                            , stdout=subprocess.PIPE) 
    

    我自己会用最后一个。

  3. 当指定shell=True 时,subprocess.Popen 对包含多个元素的列表所做的操作并没有很好的记录,因此不建议使用这种用法。 Posix 实现将列表的所有元素添加到 ["sh", "-c"],然后执行它。实际上,这将执行以下操作:

    sh -c find /home/disk1 -maxdepth 1 -name "file1*" -o -name "file7*"
    

    这里,-c 的参数只是 find/home/disk1 变为 $0$1$7 设置为其余参数。最终结果是 find 在没有命令行参数的情况下执行(在名称为 /home/disk1 的进程中)。不带参数的find 会生成从当前工作目录开始的所有文件的递归列表。

【讨论】:

  • 谢谢,glob 是我的场景所需要的,我忘记了它的存在。关于maxdepthmaxdepth 0 在shell 上非常适合我,但由于某种原因,它只能与maxdepth 1 和子进程一起使用。感谢您的帮助。
  • @rrlamichhane:根据man find:“-maxdepth 0 表示仅将测试和操作应用于命令行参数。”也许你有find 的别名,或者你写了find /home/disk1/*。耸耸肩。它确实像我的系统上记录的那样工作。
猜你喜欢
  • 1970-01-01
  • 2014-10-17
  • 1970-01-01
  • 2018-12-06
  • 2013-08-18
  • 2013-10-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多