Python subprocess 调用无效

0 投票
1 回答
2781 浏览
提问于 2025-04-18 17:59

我正在写一个Python程序,需要在我的脚本中执行一个比较长的命令,并获取输出。

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=True'去掉,这样的返回结果是: (b'', None) 我本来希望能得到4个文件的名字,但结果还是不对。谢谢。

补充:抱歉,我不是在找文件,我是在找文件夹。

1 个回答

4
  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 会从当前工作目录开始递归列出所有文件。

撰写回答