我一直在尝试使用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;它怎么能这样做?
答案 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
。如果当前目录包含名为baclava
,bnm
和hello.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(...)。
我希望这会有所帮助。