我正在尝试使用python获取目录中的CSV文件列表。这在unix中非常简单:
ls -l *.csv
而且,可以预见的是,我得到了一个以我目录中的.csv结尾的文件列表。但是,当我使用Subprocess模块尝试Python等价物时:
>>> import subprocess as sp
>>> sp.Popen(["ls", "-l", "*.csv"], stdout = sp.PIPE)
<subprocess.Popen object at 0xb780e90c>
>>> ls: cannot access *.csv: No such file or directory
有人可以解释一下发生了什么吗?
修改:添加shell = True
会删除错误,但我没有获取仅包含CSV文件的列表,而是获取所有文件列表目录。
答案 0 :(得分:4)
如果你希望它的行为与shell一样,你需要通过shell=True
(你的里程可能会有所不同,具体取决于你的系统和shell)。在您的情况下,问题是当您执行ls -l *.csv
时, shell 正在评估*表示什么,而不是ls
。 (ls
仅仅是格式化您的结果,但是shell已经完成了繁重的任务以确定哪些文件匹配*.csv
)。子流程使ls
按字面意思处理*.csv
,并查找具有该特定名称的文件,当然没有任何文件(因为这是一个非常难以创建的文件名)。
你真正应该做的是使用os.listdir
并自己过滤名称。
答案 1 :(得分:4)
为什么不使用glob呢?它会比“炮轰”更快!
import glob
glob.glob('*.csv')
这为您提供了名称,而不是所有额外信息ls -l
耗材,但您可以通过os.stat
调用感兴趣的文件来获取额外信息。
如果你真的必须使用ls -l
,我想你想把它作为一个字符串传递给shell进行所需的星形扩展:
proc = sp.Popen('ls -l *.csv', shell=True, stdout=sp.PIPE)
答案 2 :(得分:1)
当您在shell中输入ls -l *.csv
时,shell本身会将*.csv
扩展为其匹配的所有文件名列表。所以ls的参数实际上更像是ls -l spam.txt eggs.txt ham.py
ls命令本身不了解通配符。因此,当您将参数*.csv
传递给它时,它会尝试将其视为文件名,并且没有具有该名称的文件。正如Nick所说,您可以使用shell=True
参数让Python调用shell来运行子进程,shell将为您扩展通配符。
答案 3 :(得分:1)
p=subprocess.Popen(["ls", "-l", "*.out"], stdout = subprocess.PIPE, shell=True)
原因
/bin/sh -c ls -l *.out
要执行。
如果在目录中尝试此命令,您将看到 - 以典型的mystifying-shell方式 - 列出所有文件。并且-l
标志也被忽略。这是一个线索。
您看,-c
标记仅提取ls
。其余的论点被/bin/sh
吃掉了,而不是被ls
吃掉了。
要使此命令在终端上正常工作,您必须键入
/bin/sh -c "ls -l *.out"
现在/ bin / sh将完整命令“ls -l * .out”视为-c
标志的参数。
因此,要使用subprocess.Popen
来解决这个问题,最好将命令作为单个字符串传递
p=subprocess.Popen("ls -l *.out", stdout = subprocess.PIPE, shell=True)
output,error=p.communicate()
print(output)