2010-11-05 46 views
24

是否有可能用於使用getopt的或optparse一個選項取多個值,如下面的例子:使用getopt/optparse爲單個選項處理多個值?

./hello_world -c arg1 arg2 arg3 -b arg4 arg5 arg6 arg7 

請注意,實際值的每個選項的數目(-c,-b)能是1或100.我不想使用: ./hello_world -c "arg1 arg2 arg3" -b "arg4 arg5 arg6 arg7"

在我看來,這可能是不可能的(也許違反POSIX),請糾正我,如果我錯了。

我見過一些例子,可以收集行末尾的所有非選項(./hello_world -c arg1 -b arg1 arg2 arg3)...但不是多個選項中的第一個。

我想讓我的應用程序在各種不同的Python版本的平臺上工作,所以我沒有看過argparser。

回答

5

您可以使用Python2.7附帶的​​中的nargs參數和可下載的here來完成此操作。

我認爲這是​​不屬於optparse的改進之一。所以,不幸的是,我不認爲有一個很好的方法來處理這個optparsegetopt(這是更舊的)。

一個快速和骯髒的解決方案可能是放棄optparse/getop/argparse,只是自己解析sys.argv

或者,在相反的方向走,你可能會考慮包裝argparse的凍結副本(〜88K)(更名像argparse_static)與您的程序,並 導入像這樣:

try: 
    import argparse 
except ImportError: 
    import argparse_static as argparse 

那如果安裝了該程序,程序將使用​​,如果不是,則將使用argparse_static。最重要的是,您不必重寫很多代碼,因爲​​成爲標準。

+0

非常感謝您提供了兩個快速而深入的答案。我確實設法編寫自己的選項解析器來處理事情。下載argparse的靜態副本並不是我考慮過的,但現在已經在桌面上了。 – 2010-11-05 21:01:22

+0

我的投票與argparse。比optparse更容易得到我的頭腦。 (在Optik之前,我是一個在optparse中進行黑客攻擊的人,在它進入標準庫之前) – 2010-11-05 22:18:55

5

getopt和optparse都不支持。另外,在默認(GNU)模式下,附加參數將被視爲散佈參數,即在處理結束時變爲可作爲剩餘參數。

公約將是需要重複同樣的說法提,即

./hello_world -c arg1 -c arg2 -c arg3 -b arg4 -b arg5 -b arg6 -b arg7 

這將支撐。

如果您絕對想按照您指定的方式工作(即,-b和-c擴展到下一個參數或參數列表的末尾),那麼您可以根據optparse一起破解一些東西。從OptionParser繼承,並覆蓋_process_short_opts。如果它是您的選項之一,請在子類中處理它,否則轉發到基類。

+1

謝謝你解釋這個約定。這就是我想.. 問題是,每個選項的值的數量使得使用該公約非用戶友好。我想我最終可能會通過sys.argv進行迭代並自行處理。 – 2010-11-05 21:11:33

14

是的,可以使用optparse完成。

這是一個例子:

./test.py --categories=aaa --categories=bbb --categories ccc arg1 arg2 arg3 

它打印:

arguments: ['arg1', 'arg2', 'arg3'] 
options: {'categories': ['aaa', 'bbb', 'ccc']} 

全部工作實施例以下:

#!/usr/bin/env python 

import os, sys 
from optparse import OptionParser 
from optparse import Option, OptionValueError 

VERSION = '0.9.4' 

class MultipleOption(Option): 
    ACTIONS = Option.ACTIONS + ("extend",) 
    STORE_ACTIONS = Option.STORE_ACTIONS + ("extend",) 
    TYPED_ACTIONS = Option.TYPED_ACTIONS + ("extend",) 
    ALWAYS_TYPED_ACTIONS = Option.ALWAYS_TYPED_ACTIONS + ("extend",) 

    def take_action(self, action, dest, opt, value, values, parser): 
     if action == "extend": 
      values.ensure_value(dest, []).append(value) 
     else: 
      Option.take_action(self, action, dest, opt, value, values, parser) 


def main(): 
    PROG = os.path.basename(os.path.splitext(__file__)[0]) 
    long_commands = ('categories') 
    short_commands = {'cat':'categories'} 
    description = """Just a test""" 
    parser = OptionParser(option_class=MultipleOption, 
          usage='usage: %prog [OPTIONS] COMMAND [BLOG_FILE]', 
          version='%s %s' % (PROG, VERSION), 
          description=description) 
    parser.add_option('-c', '--categories', 
         action="extend", type="string", 
         dest='categories', 
         metavar='CATEGORIES', 
         help='comma separated list of post categories') 

    if len(sys.argv) == 1: 
     parser.parse_args(['--help']) 

    OPTIONS, args = parser.parse_args() 
    print "arguments:", args 
    print "options:", OPTIONS 

if __name__ == '__main__': 
    main() 

更多信息在http://docs.python.org/library/optparse.html#adding-new-actions

4

另一種選擇是定義分隔符並在本地處理它,如mount命令中的選項。

例如,如果,可以作爲分隔符:

... 
args, _ = getopt.getopt(sys.argv[1:],'b:') 
for flag, arg in args: 
    if flag=='-b': all_arguments = arg.split(',') 
... 

$ ./test -b opt1,opt2,opt3 

相同的空間!但是,用戶必須正確引用它。

$ ./test -b 'opt1 opt2 opt3' 
7

不好意思來晚了,但我剛剛用optparse使用了nargs標誌解決了這個問題。

parser.add_option('-c','--categories', dest='Categories', nargs=4) 

http://docs.python.org/2/library/optparse.html#optparse.Option.nargs

這也是值得注意的,即argparse(由unutbu建議的)現在是標準Python分佈的一部分,同時optparse被棄用。

+0

假設如果我想把這裏的支票,如果用戶沒有輸入參數。如何將4個參數逐一讀入「option.Categories」 – kzs 2014-06-18 06:55:20

+1

請注意,這限制了'-c'的4個參數。 – Plasma 2015-08-06 22:20:25

+0

從@Plasma開始,它也需要4個參數,不多也不少。 – sijpkes 2017-10-05 03:17:29

8

儘管有其他評論的聲明,但這對於香草optparse是可能的,至少在python 2.7中是這樣。你只需要使用action =「append」。從docs

parser.add_option("-t", "--tracks", action="append", type="int") 

如果-t3上看到命令行,optparse確實相當於:

options.tracks = [] 
options.tracks.append(int("3")) 

如果稍後上,--tracks = 4所看到的,它的作用:

options.tracks.append(int("4")) 
+1

這是一個比較傳統的解決方案。將多個參數傳遞給單個標誌是一種誤導性練習,並且很有可能導致問題出現。如果您需要將IFS分隔的單詞傳遞給*選項*,我鼓勵用戶引用該值,然後在代碼中對其進行分割。否則,請按照本答案中的建議使用命令參數或重複標誌。 – Ben 2016-07-06 17:07:27

3

更簡單的一個:

make_option(
    "-c", 
    "--city", 
    dest="cities", 
    action="append", 
    default=[], 
    help="specify cities", 
) 

Append action是解決此問題的最簡單解決方案。

相關問題