Python 磁盘使用脚本

Python 磁盘使用脚本,python,diskspace,Python,Diskspace,某处事情停止了。其目的是,如果未提供参数,则显示当前磁盘使用情况;如果作为参数提供,则显示目录的使用情况;如果提供了名为--all的参数,则显示所有子目录的磁盘使用情况。这是我到目前为止得到的。由于某些原因,现在为目录提供“-d”时失败 #!/usr/bin/env python import os import sys import subprocess import getopt from humanize import naturalsize def get_size(star

某处事情停止了。其目的是,如果未提供参数,则显示当前磁盘使用情况;如果作为参数提供,则显示目录的使用情况;如果提供了名为--all的参数,则显示所有子目录的磁盘使用情况。这是我到目前为止得到的。由于某些原因,现在为目录提供
“-d”
时失败

#!/usr/bin/env python

import os 
import sys 
import subprocess 
import getopt 
from humanize import naturalsize

def get_size(start_path = '.'):
    total_size = 0
    for dirpath, dirnames, filenames in os.walk(start_path):
        for f in filenames:
            fp = os.path.join(dirpath, f)
            total_size += os.path.getsize(fp)
    return total_size

def get_immediate_subdirectories(a_dir):
    return [name for name in os.listdir(a_dir)
            if os.path.isdir(os.path.join(a_dir, name))]

def version():
    print ("Version: 1.0")

def usage():
    print ("Usage: disk_usage.py [-a|--all][-n|--ncdu][-v|--version][directory name]")

def main():
    try:
        opts, args = getopt.getopt(sys.argv[1:], "adhnv", ["all","directory","help","ncdu","version",])
    except getopt.GetoptError as err:
        # print help information and exit:
        print(err)  # will print something like "option -a not recognized"
        usage()
        sys.exit(2)
    for o, a in opts:
        if o in ("-a", "--all"):
            for subdir in get_immediate_subdirectories('.'):
                print ("%s\t\t %s" % (naturalsize(get_size(subdir)),subdir))
                sys.exit()
        elif o in ("-d", "--directory"):
            print (naturalsize(get_size(start_path=sys.argv[1:])))
        elif o in ("-v", "--version"):
            print (version())
            sys.exit()
        elif o in ("-h", "--help"):
            usage()
            sys.exit()
        elif o in ("-n", "--ncdu"):
            os.system('ncdu')
            sys.exit()
        else:
            print (usage())


main()

我想我现在明白了。第42行包括sys.argv[1:],它返回了一个列表。在提供了-d选项之后,引用目录实际上应该是sys.argv[2]。

我发现使用
getopt时有几个问题。其中一个(听起来像是你自己弄明白的)是,通过传递
start\u path=sys.argv[1://code>将
start\u path
分配给第一个命令参数之后所有命令参数的
列表,你给
get\u size()
的东西是错误的

第二个问题是没有正确定义传递给
getopt()
的第二个和第三个参数。引述:

第二个参数是单字符选项的选项定义字符串如果其中一个选项需要参数,则其字母后跟冒号。

(强调矿山)

这意味着为了接受带有
-d
选项的值,您需要使用
“ad:hnv”
,而不是您已经得到的
“adhnv”

类似地,对于长样式选项列表中的
--directory
选项:

第三个参数(若使用)应该是一系列长样式选项名。长样式选项可以是多个字符,例如--noarg或--witharg。序列中的选项名称不应包含“-”前缀如果任何长选项需要参数,则其名称的后缀应为“=”

要支持它,也需要您传递
[“全部”,“目录=”,“帮助”,“ncdu”,“版本”]

不幸的是,
getopt
不支持具有可选选项参数。原因很可能是因为它使解析变得模棱两可:例如,如果
-a
采用可选参数,而
-b
完全是另一个选项,则不清楚如何解释
-ab

如果您能够接受该限制,则以下内容包含了解决上述问题的更改:

import os
import sys
import subprocess
import getopt
from humanize import naturalsize

def get_size(start_path='.'):
    # Might was to check validity of path here...
    #if not (os.path.exists(start_path) and os.path.isdir(start_path)):
    #    raise ValueError('Invalid path argument: {!r}'.format(start_path))
    total_size = 0
    for dirpath, dirnames, filenames in os.walk(start_path):
        for f in filenames:
            fp = os.path.join(dirpath, f)
            total_size += os.path.getsize(fp)
    return total_size

def get_immediate_subdirectories(a_dir):
    return [name for name in os.listdir(a_dir)
            if os.path.isdir(os.path.join(a_dir, name))]

def version():
    print("Version: 1.0")

def usage():
    print("Usage: disk_usage.py [-a|--all][-n|--ncdu][-v|--version][directory name]")

def main():
    try:
        opts, args = getopt.getopt(sys.argv[1:], "ad:hnv",
                            ["all", "directory=", "help", "ncdu", "version",])
    except getopt.GetoptError as err:
        print(err)
        usage()
        if __name__ == '__main__':
            return 2  # Unit test.
        else:
            sys.exit(2)

    for opt, arg in opts:
        if opt in ("-a", "--all"):
            for subdir in get_immediate_subdirectories('.'):
                print("%s\t\t %s" % (naturalsize(get_size(subdir)), subdir))
                sys.exit()
        elif opt in ("-d", "--directory"):
            print(naturalsize(get_size(start_path=arg)))
        elif opt in ("-v", "--version"):
            print(version())
            sys.exit()
        elif opt in ("-h", "--help"):
            usage()
            sys.exit()
        elif opt in ("-n", "--ncdu"):
            os.system('ncdu')
            sys.exit()
        else:
            print(usage())
    else:
        print(usage())


if __name__ == '__main__':
    # Unit test.
    sys.argv = ['disk_usage.py']  # no option given
    main()
    sys.argv = 'disk_usage.py -d.'.split()  # short opt
    main()
    sys.argv = 'disk_usage.py -dsome_folder'.split()  # short opt
    main()
    sys.argv = 'disk_usage.py -d some_folder'.split()  # short opt
    main()
    sys.argv = 'disk_usage.py --directory some_folder'.split()  # long opt
    main()
    sys.argv = 'disk_usage.py -d'.split()  # Missing argument error
    main()

这里有两个问题


第一个问题是您使用的
getopt
错误:

opts, args = getopt.getopt(sys.argv[1:], "adhnv", ["all","directory","help","ncdu","version",])
这将返回选项列表
opts
,以及过滤掉选项的
args
。但是您继续使用
sys.argv
而不是
args

print (naturalsize(get_size(start_path=sys.argv[1:])))
在像
myprogram-d spam
这样的调用中,
sys.argv[1://code>将是
['-d',spam']
。但是您不想要
-d
。这就是您首先调用
getopts
的全部原因。因此,在这里使用
args
,而不是
sys.argv


第二个问题是,您正在获取一个切片,
sys.argv[1://code>,但将其视为一个值,而不是一个值列表

如果要允许使用
-d
传递多个目录并处理所有目录,则需要在切片上使用
for arg in…:
循环

如果只需要一个目录,那么只需对列表进行索引,如
[1]
,而不是
[1://code>。尽管如此,如果您希望这样做,您可能不希望
-d
成为布尔标志,目录成为arg;您希望
-d
成为一个以目录作为其值的标志


更一般地说,您可能首先不应该在这里使用
getopt
。比如说:

请注意,
getopt
模块是命令行选项的解析器,其API设计为C
getopt()
函数的用户所熟悉。不熟悉C<代码> GETopt()/Cux>函数的用户或想编写更少代码并获得更好帮助和错误消息的用户应考虑使用该模块。
如果你是一个
getopt
向导,那么一定要对简单的项目使用
getopt
,而不是学习新的东西,即使它更好。但是对于其他人来说,首先学习
getopt
确实没有什么好的理由,更不用说学习如何调试它的所有古怪角落了
argparse
在各个方面都非常好。如果您不喜欢
argparse
,PyPI上有六种选择。

由于某种原因,它现在失败了
,它到底是如何失败的?错误消息?预期与实际行为?什么改变了?我们不仅仅是要挖掘你的代码,盲目地修复一个我们甚至不知道是什么问题的问题。作为一个旁注:你写这个脚本是为了学习,还是因为你需要一个可以做这些事情的工具?因为像
df
du
这样的工具已经存在了,除非你在Windows上,如果你是……我很确定,即使我不知道它是什么(可能是Mark Russinovich的系统内部组件的一部分?)。但是如果你这样做是为了学习如何使用
walk
listdir
stat
等等,那么这是一个非常合理的项目(尽管我建议你学习
scandir
,还有
argparse
而不是
getopt
)。是的,我正在学习编码。我确实喜欢ncdu,所以我把它包括在选项中。我想用一个命令立即告诉我一个目录的递归大小,但也可以选择对所有子目录进行递归。我得到的错误是:选项-d我得到一个TypeError,强制使用Unicode,需要找到字符串或缓冲区列表。如果没有给出任何选项,它将不返回任何内容,而不是当前目录的递归大小。其他选项似乎都可以工作,我相信有人能给我一个使用argpa的示例吗