Python中find2perl的等价物
Perl 有一个很棒的小工具叫做 find2perl,它可以把 Unix 的 find
命令行转换成 Perl 脚本,功能非常相似。
比如你有一个这样的 find 命令:
find /usr -xdev -type d -name '*share'
^^^^^^^^^^^^ => name with shell expansion of '*share'
^^^^ => Directory (not a file)
^^^ => Do not go to external file systems
^^^ => the /usr directory (could be multiple directories
这个命令会找到所有在 /usr
目录下以 share
结尾的文件夹。
然后你可以运行 find2perl /usr -xdev -type d -name '*share'
,它会生成一个 Perl 脚本来完成同样的事情。你可以根据自己的需要修改这个脚本。
Python 也有一个 os.walk()
函数,确实可以实现递归列出目录的功能,但它和 find
还是有很大不同的。
举个简单的例子,使用 find . -type f -print
来查找并打印当前目录下的所有文件。如果用 os.walk()
来简单实现的话,代码可能是:
for path, dirs, files in os.walk(root):
if files:
for file in files:
print os.path.join(path,file)
不过,这样的结果和在命令行输入 find . -type f -print
的结果会不一样。
我还测试了不同的 os.walk()
循环,比较它们的结果:
# create pipe to 'find' with the commands with arg of 'root'
find_cmd='find %s -type f' % root
args=shlex.split(find_cmd)
p=subprocess.Popen(args,stdout=subprocess.PIPE)
out,err=p.communicate()
out=out.rstrip() # remove terminating \n
for line in out.splitlines()
print line
主要的区别在于,os.walk()
会把链接文件也算作文件,而 find
则会跳过这些链接。
所以,要想实现和 find . -type f -print
一样的效果,正确的实现应该是:
for path, dirs, files in os.walk(root):
if files:
for file in files:
p=os.path.join(path,file)
if os.path.isfile(p) and not os.path.islink(p):
print(p)
由于 find
有成百上千种不同的用法和副作用,测试每一种变体会非常耗时。因为 find
在 POSIX 世界中是计算树形结构中文件数量的标准,所以在 Python 中以相同的方式实现这一点对我来说很重要。
那么,Python 有没有类似于 find2perl
的工具呢?到目前为止,我一直在使用 find2perl
,然后手动把 Perl 代码翻译成 Python。这很困难,因为 Perl 的文件测试操作符有时和 Python 的 os.path
文件测试是 不同 的。
4 个回答
我觉得glob这个工具可以帮助你实现这个功能。
如果你想要完全重新实现 find
这个命令,那你的代码可能会变得非常复杂。其实 find
本身就已经挺复杂的了。
不过在大多数情况下,你并不需要复制 find
的所有功能;你只是想做一些更简单的事情,比如“找出所有以 .txt 结尾的文件”。如果你真的需要 find
的全部功能,直接运行 find
命令,看看输出就行了。正如你所说的,它是一个标准工具,直接使用它是最好的选择。
我经常写一些代码来读取 stdin
上的路径,这样我就可以做到这一点:
find ...a bunch of filters... | my_python_code.py
这里有一些观察和几段代码,可以帮助你入门。
首先,Python可以像Perl一样执行这种形式的代码:
cat code.py | python | the rest of the pipe story...
find2perl
是一个聪明的代码模板,它根据find的模板生成一个Perl函数。因此,只要复制这个模板,你就不会遇到你所说的“成百上千种变化”。
其次,find2perl
的结果并不是完美的,因为不同版本的find(比如GNU或BSD)之间可能会有差异。
第三,默认情况下,os.walk
是从下往上遍历的,而find
是从上往下的。如果你的目录结构在递归过程中发生变化,结果就会不同。
有两个Python项目可能对你有帮助:twander和dupfinder。这两个项目都力求与操作系统无关,并且像find
一样递归文件系统。
如果你在Python中创建一个通用的find
函数,可以设置os.walk
从上往下递归,使用glob来模拟shell扩展,并参考这两个项目中的一些代码,你就可以比较轻松地复制find2perl
的功能。
抱歉我无法提供一个现成的解决方案来满足你的需求……