使用Python的os.walk函数和ls命令得到不同的结果

4
#!/bin/python
import os
pipe=os.popen("ls /etc -alR| grep \"^[-l]\"|wc -l")         #Expr1
a=int(pipe.read())
pipe.close()
b=sum([len(files) for root,dirs,files in os.walk("/etc")])  #Expr2
print a
print b
print "a equals to b ?", str(a==b)  #False
print "Why?"

Expr1Expr2有什么区别?它们都与IT技术有关。我认为Expr1给出了正确答案,但不确定。

3个回答

4

简短回答:

ls -laR | grep "^[-l]" 可以计算目录符号链接的数量。它匹配任何以 l 开头且包含目录符号链接的行。

相比之下,[files for root, dirs, files in os.walk('/etc')] 不会计算目录符号链接的数量。它忽略所有目录,只列出文件。


详细回答:

以下是我如何确定差异的方法:

import os
import subprocess
import itertools

def line_to_filename(line):
    # This assumes that filenames have no spaces, which is a false assumption
    # Ex: /etc/NetworkManager/system-connections/Wired connection 1
    idx = line.rfind('->')
    if idx > -1:
        return line[:idx].split()[-1]
    else:
        return line.split()[-1]

line_to_filename 试图在 ls -laR 的输出中找到文件名。

这定义了 expr1expr2,并且本质上与您的代码相同。

proc=subprocess.Popen(
    "ls /etc -alR 2>/dev/null | grep -s \"^[-l]\" ", shell = True,
    stdout = subprocess.PIPE)         #Expr1
out, err = proc.communicate()
expr1 = map(line_to_filename, out.splitlines())

expr2 = list(itertools.chain.from_iterable(
    files for root,dirs,files in os.walk('/etc') if files))  #Expr2

for expr in ('expr1', 'expr2'):
    print '{e} is of length {l}'.format(e = expr, l = len(vars()[expr]))

这将从expr1中删除与expr2中相同的名称:

for name in expr2:
    try:
        expr1.remove(name)
    except ValueError:
        print('{n} is not in expr1'.format(n = name))

在删除expr1expr2共有的文件名后,

print(expr1) 

收益率
['i386-linux-gnu_xorg_extra_modules', 'nvctrl_include', 'template-dkms-mkdsc', 'run', '1', 'conf.d', 'conf.d']

然后我使用 find/etc 中查找这些文件,并试图猜测这些文件的不寻常之处。它们是指向目录的符号链接(而不是文件)。


非常感谢您详细的回答。 - JacquesW

1

如果您使用walk命令,错误将被忽略(请参见this),而ls命令会为每个错误发送一条消息。这些都算作单词。


1
错误消息将被发送到标准错误,而不是管道。 - chepner
1
如果一切顺利,你可以依靠“..”和“.”来计算ls。此外,它必须是ls -alR /etc ... - f p
1
“sum([len(files) for root,dirs,files in os.walk("/etc",onerror=some_function)])” 能得到正确的答案吗?还有,“some_function”该怎么处理? - JacquesW

0
在我的机器上,/etc 是一个指向 /private/etc 的符号链接,因此 ls /etc 只有一行输出。ls /etc/ 给出了 lsos.walk 之间预期的等价性。

/ etc 只是一个例子,实际上它可以是任何目录。这两个表达式经常会给出不同的答案。 - JacquesW
1
你在运行什么疯狂的发行版,会将符号链接 /etc 作为目标? - Falmarri
1
@Falmarri NeXTStep或其后代,例如OSX和iOS。 - mmmmmm

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接