使用glob参数递归匹配文件名

时间:2011-05-23 22:25:57

标签: python bash glob argv

我一直在尝试使用sys.argv[1]glob.glob以递归方式获取命令行参数(os.walk)中与glob模式匹配的文件列表。问题是,bash(以及它看起来很多其他shell)会自动将glob模式扩展为文件名。

标准的unix程序(例如grep -R)如何执行此操作?我意识到他们不是在python中,但如果这种情况发生在shell级别,那应该不重要,对吧?有没有办法让脚本告诉shell不自动扩展glob模式?看起来set -f将禁用globbing,但我不确定如何尽早运行,可以这么说。

我见过Use a Glob() to find files recursively in Python?,但这并不包括从命令行参数中实际获取glob模式。

谢谢!

编辑:

类似grep的perl脚本ack接受perl正则表达式作为其参数之一。因此,ack .*打印出每个文件的每一行。但是.*应该扩展到目录中的所有隐藏文件。我试过阅读剧本,但我不知道perl;它怎么能这样做?

3 个答案:

答案 0 :(得分:6)

shell甚至在考虑调用命令之前执行glob扩展。诸如grep之类的程序不会做任何事情来阻止通配:它们不能。作为这些程序的调用者,您必须告诉shell您要将*?等特殊字符传递给程序,而不要让shell解释它们。你可以把它们放在引号内:

grep -E 'ba(na)* split' *.txt

(在所有名为< something> ba split的文件中查找bana split.txt等等。在这种情况下,单引号或双引号都可以解决问题。在单引号之间,shell不会扩展。在双引号之间,仍会解释$`\。您还可以通过在反斜杠前面加上单个字符来保护shell扩展。这不仅是需要保护的通配符;例如,在上面,模式中的空格是引号,因此它是grep的参数的一部分而不是参数分隔符。编写上述代码段的其他方法包括

grep -E "ba(na)* split" *.txt
grep -E ba\(na\)\*\ split *.txt

对于大多数shell,如果参数包含通配符但模式与任何文件都不匹配,则模式保持不变并传递给基础命令。所以像

这样的命令
grep b[an]*a *.txt

具有不同的效果,具体取决于系统上存在的文件。如果当前目录不包含名称以b开头的任何文件,则该命令将搜索名称与b[an]*a匹配的文件中的模式*.txt。如果当前目录包含名为baclavabnmhello.txt的文件,则该命令将扩展为grep baclava bnm hello.txt,因此它会搜索两个文件中的模式baclava { {1}}和bnm。不用说,在脚本中依赖它是一个坏主意;在命令行上,它偶尔会保存打字,但这样做很危险。

在不包含点文件的目录中运行hello.txt时,shell运行ack .*。然后,ack . ..命令的行为将在ack下的所有文件中打印出所有非空行(模式.:匹配任何一个字符)(递归地,当前目录的父级。与..对比,ack '.*'搜索当前目录及其子目录中的模式.*(匹配任何内容)(由于ack在您未传递任何文件名参数时的行为)

答案 1 :(得分:1)

说到grep,它只是接受一个文件名列表,而不是自己进行glob扩展。如果您确实需要将模式作为参数传递,则必须在命令行中使用单引号引用它。但在此之前,请考虑让shell完成它的设计工作。

答案 2 :(得分:1)

是的,set -f,你走在正确的轨道上。

听起来你要从shell调用你的python程序。

每次使用shell发出命令时,它都会尝试扫描cmd-line并处理通配符,命令替换以及其他一大堆内容。

所以你必须在命令行上运行程序之前关闭全局

set -f
echo *
*

myprogram *.txt

会将字符串'* .txt'传递给您的程序。然后,您可以使用内部通配符来获取文件。

或者你可以通过创建包装器脚本来完成同样的事情

 #!/bin/bash
 set -f
 myProgram ${@}

其中${@} are the arguments you pass in when you start myProgram`来自命令行-line,crontab或来自另一个进程的exec(...)。

我希望这会有所帮助。