15

Perl 有一个可爱的小实用程序,称为find2perl,它将(非常忠实地)将 Unix 实用程序的命令行find转换为 Perl 脚本以执行相同的操作。

如果您有这样的查找命令:

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

它找到所有以share下面结尾的目录/usr

现在运行find2perl /usr -xdev -type d -name '*share',它会发出一个 Perl 脚本来做同样的事情。然后,您可以修改脚本以供您使用。

Python 有os.walk()其中当然有需要的功能,递归目录列表,但是有很大的不同。

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但是,这将产生与在 shell 中键入不同的结果。

我也一直在测试各种 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 跳过这些。

因此,与以下相同的正确实现file . -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是 POSIX 世界中关于如何计算树中文件的黄金标准,因此在 Python 中以同样的方式进行操作对我来说很重要。

find2perl那么有没有可以用于 Python的等价物?到目前为止,我一直在使用find2perl并手动翻译 Perl 代码。这很难,因为 Perl 文件测试运算符有时与 os.path 中的 Python 文件测试不同。

4

4 回答 4

4

如果您尝试重新实现所有find. find本身就很毛茸茸。

但是,在大多数情况下,您并没有尝试复制 find 的完整行为。您正在执行一项更简单的任务(例如,“查找所有以 .txt 结尾的文件”)。如果你真的需要所有的find,只需运行find并阅读输出。正如您所说,这是黄金标准;你不妨只使用它。

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

find ...a bunch of filters... | my_python_code.py
于 2011-09-25T01:14:28.340 回答
2

有一些观察结果和几段代码可以帮助您。

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

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

find2perl是一个聪明的代码模板,它基于 find 模板发出 Perl 函数。因此,复制此模板,您将不会拥有您所感知的“数百种排列”。

其次,结果find2perl并不完美,就像 GNU 或 BSD 等 find 版本之间存在潜在差异一样。

第三,默认os.walk是自下而上;find是自上而下的。如果您的底层目录树在您递归它时发生变化,这会产生不同的结果。

Python 中有两个项目可以帮助您:twanderdupfinder。每个都力求独立于操作系统,并且每个都递归文件系统,如find.

如果您find在 Python 中模板化一个通用的类似函数,设置os.walk为自顶向下递归,使用 glob 复制 shell 扩展,并使用您在这两个项目中找到的一些代码,您可以轻松复制find2perl

抱歉,我无法指出可以满足您需求的东西...

于 2011-10-02T22:42:00.540 回答
1

我认为glob可以帮助您实现这一点。

于 2011-09-30T00:30:52.213 回答
1

我编写了一个 Python 脚本用于os.walk()搜索和替换;在写这样的东西之前看看它可能是一件有用的事情。

用 Python 替换文件中的字符串

并且 find(1) 的任何 Python 替代品都将严重依赖os.stat()检查文件的各种属性。例如, find(1) 有一些标志来检查文件的大小或最后修改的时间戳。

于 2011-09-30T01:40:51.697 回答