Python中find2perl的等价物

15 投票
4 回答
1490 浏览
提问于 2025-04-17 03:01

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 个回答

1

我觉得glob这个工具可以帮助你实现这个功能。

4

如果你想要完全重新实现 find 这个命令,那你的代码可能会变得非常复杂。其实 find 本身就已经挺复杂的了。

不过在大多数情况下,你并不需要复制 find 的所有功能;你只是想做一些更简单的事情,比如“找出所有以 .txt 结尾的文件”。如果你真的需要 find 的全部功能,直接运行 find 命令,看看输出就行了。正如你所说的,它是一个标准工具,直接使用它是最好的选择。

我经常写一些代码来读取 stdin 上的路径,这样我就可以做到这一点:

find ...a bunch of filters... | my_python_code.py
2

这里有一些观察和几段代码,可以帮助你入门。

首先,Python可以像Perl一样执行这种形式的代码:

 cat code.py | python | the rest of the pipe story...

find2perl是一个聪明的代码模板,它根据find的模板生成一个Perl函数。因此,只要复制这个模板,你就不会遇到你所说的“成百上千种变化”。

其次,find2perl的结果并不是完美的,因为不同版本的find(比如GNU或BSD)之间可能会有差异。

第三,默认情况下,os.walk是从下往上遍历的,而find是从上往下的。如果你的目录结构在递归过程中发生变化,结果就会不同。

有两个Python项目可能对你有帮助:twanderdupfinder。这两个项目都力求与操作系统无关,并且像find一样递归文件系统。

如果你在Python中创建一个通用的find函数,可以设置os.walk从上往下递归,使用glob来模拟shell扩展,并参考这两个项目中的一些代码,你就可以比较轻松地复制find2perl的功能。

抱歉我无法提供一个现成的解决方案来满足你的需求……

撰写回答