Python Argparse 无法分割字符串

1 投票
2 回答
3635 浏览
提问于 2025-04-20 03:32

这件事应该很简单,但现在让我有点困扰。我设置了一个简单的命令行参数解析工具(argparse),想要在字符串中如果有减号就把它分开。听起来很简单,但当我把这些参数传给argparse时,它却显示为空。所以我想给你看看我想做的事情,以及为什么我觉得很困惑。注意:我已经明确指定它是一个字符串。使用dir和type函数时也显示为空。

        import argparse
        import sys
        portlist = []

        #Parser Arguments and Usage
        parser = argparse.ArgumentParser(description='This script performs a Syn scan on a specific host with the ports that are specified by you.', usage='Specify Ports with the -p switch. Port range -p 80-200, specific port -p 80, multiple ports -p 80,443,25,22', add_help=True) 
        parser.add_argument('-p', action='store', dest='argPorts', help='Type ports in like follows.  For a range -p 80-200, for a group of ports -p 443,80,25,22 or single port -p 80', required=True, type=str) 
        parser.add_argument('-d', action='store', dest='destIP', help='Type dest IP in this field.  i.e. 192.168.0.5', required=True)
        parser.add_argument('-t', action='store', dest='threadCount', help='Type the amount of threads to use as an integer', type=int, required=True)

        if len(sys.argv)<3:
            parser.print_help()
                sys.exit(0)
        opts = vars(parser.parse_args())

        options = parser.parse_args()
        argPorts = options.argPorts
        destIP = options.destIP
        threadCount = options.threadCount

        if argPorts.find(','):
            print "comma"
            for p in argPorts.split(','):
                portlist.append(p)

        elif argPorts.find('-'):
            print "range"
            portlist.append(argPorts.split('-')[0])
            portlist.append(argPorts.split('-')[1])

        else:
            print "no"


        print portlist

我在命令行中这样使用它:
python test.py -t 10 -p "80-100" -d "192.168.136.131"

我想把80和100分开成两个变量。但它不工作 :(

下面的回答很棒。

这里有个很好的解释,适合像我这样的人 http://www.pythoncentral.io/how-to-see-if-a-string-contains-another-string-in-python/

2 个回答

1

你可以把处理端口的逻辑放到一个函数里,然后把这个函数作为type传给你的add_argument('-p'),这样还可以添加一些用户友好的错误提示,像这样:

def parse_port(port):
    if port.isdigit():
        return int(port)
    else:
        raise argparse.ArgumentTypeError(
                "'{}' is not a valid port".format(port))

def parse_port_range(port_range):
    range_members = port_range.split("-")
    if len(range_members) != 2:
        raise argparse.ArgumentTypeError(
                "'{}' is not a valid port range".format(port_range))
    actual_range = range(parse_port(range_members[0]),
                         parse_port(range_members[1]) + 1)
    return actual_range

def parse_ports(port_string):
    #first break commas
    port_groups = port_string
    if ',' in port_string:
        port_groups = port_string.split(",")            

    #then figure out ranges and populate the set of ports
    ports = set()
    for port_group in port_groups:
        if "-" in port_group:
            port_range = parse_port_range(port_group)
            ports.update(port_range)
        else: # single port
            ports.add(parse_port(port_group))
    return list(ports)

#finally create your CLI argument
parser.add_argument('-p', dest='argPorts', type=parse_ports,
                    help=('Type ports in like follows.  For a range -p 80-200, '
                          'for a group of ports -p 443,80-200,25,22 or single '
                          'port -p 80'))

在你调用parser.parse_args()之后,options.argPorts里会包含一个整数端口的列表。如果用户输入的端口有问题,就会收到一个有帮助的提示信息。

2

问题是,如果找不到搜索的字符串,.find() 方法会返回 -1。所以你不能仅仅通过是否存在来检查。

你可以试试这样的写法:

if argPorts.find(',') != -1:
    ...
elif argPorts.find('-') != -1:
    ...

我更喜欢这样的写法:

if ',' in argPorts:
    print("comma")
    for p in argPorts.split(','):
        portlist.append(p)
elif '-' in argPorts:
    print("range")
    portlist.append(argPorts.split('-')[0])
    portlist.append(argPorts.split('-')[1])
else:
    print("no")

另外,我觉得你想要在给定一个范围时创建一个端口列表。

for port in range(int(argPorts.split('-')[0]), int(argPorts.split('-')[1])+1):
    portlist.append(port)

撰写回答