วิธีที่ดีที่สุดในการแยกวิเคราะห์บรรทัดคำสั่งคืออะไร [ปิด]


251

สิ่งที่ง่ายที่สุด , tersestและส่วนใหญ่มีความยืดหยุ่นวิธีการหรือห้องสมุดสำหรับการแยกหลามอาร์กิวเมนต์บรรทัดคำสั่ง?

คำตอบ:


183

คำตอบนี้แสดงให้เห็นoptparseว่าแบบไหนเหมาะกับงูหลามรุ่นเก่า สำหรับงูหลาม 2.7 และสูงกว่าแทนที่argparse optparseดูคำตอบนี้สำหรับข้อมูลเพิ่มเติม

ในฐานะที่เป็นคนอื่นชี้ให้เห็นว่าคุณจะดีกว่าไปกับ optparse มากกว่า getopt getopt เป็นการทำแผนที่แบบหนึ่งต่อหนึ่งของฟังก์ชั่นไลบรารีมาตรฐาน getopt (3) C และไม่ได้ใช้งานง่ายนัก

optparse ในขณะที่ verbose มากขึ้นเล็กน้อยมีโครงสร้างที่ดีขึ้นและง่ายต่อการขยายในภายหลัง

นี่คือบรรทัดทั่วไปในการเพิ่มตัวเลือกใน parser ของคุณ:

parser.add_option('-q', '--query',
            action="store", dest="query",
            help="query string", default="spam")

มันค่อนข้างพูดสำหรับตัวเอง; เวลาประมวลผลจะยอมรับ -q หรือ - แบบสอบถามเป็นตัวเลือกเก็บอาร์กิวเมนต์ในแอตทริบิวต์ที่เรียกว่าแบบสอบถามและมีค่าเริ่มต้นหากคุณไม่ได้ระบุไว้ นอกจากนี้ยังเป็นการจัดทำเอกสารด้วยตนเองเมื่อคุณประกาศอาร์กิวเมนต์วิธีใช้ (ซึ่งจะใช้เมื่อเรียกใช้ด้วย -h / - วิธีใช้) ตรงนั้นพร้อมตัวเลือก

คุณมักจะแยกวิเคราะห์ข้อโต้แย้งของคุณด้วย:

options, args = parser.parse_args()

โดยค่าเริ่มต้นจะแยกวิเคราะห์อาร์กิวเมนต์มาตรฐานที่ส่งไปยังสคริปต์ (sys.argv [1:])

options.query จะถูกตั้งค่าเป็นค่าที่คุณส่งไปยังสคริปต์

คุณสร้างโปรแกรมวิเคราะห์คำง่ายๆโดยทำ

parser = optparse.OptionParser()

นี่คือพื้นฐานทั้งหมดที่คุณต้องการ นี่คือสคริปต์ Python ฉบับสมบูรณ์ที่แสดงสิ่งนี้:

import optparse

parser = optparse.OptionParser()

parser.add_option('-q', '--query',
    action="store", dest="query",
    help="query string", default="spam")

options, args = parser.parse_args()

print 'Query string:', options.query

หลาม 5 บรรทัดที่แสดงพื้นฐาน

บันทึกใน sample.py และเรียกใช้ครั้งเดียวด้วย

python sample.py

และอีกครั้งด้วย

python sample.py --query myquery

นอกเหนือจากนั้นคุณจะพบว่า optparse นั้นง่ายต่อการขยาย ในหนึ่งในโปรเจคของฉันฉันสร้างคลาสคำสั่งที่ให้คุณซ้อนคำสั่งย่อยในทรีคำสั่งได้อย่างง่ายดาย มันใช้ optparse อย่างหนักเพื่อเชื่อมโยงคำสั่งเข้าด้วยกัน มันไม่ใช่สิ่งที่ฉันสามารถอธิบายได้อย่างง่ายดายในไม่กี่บรรทัด แต่รู้สึกอิสระที่จะเรียกดูในพื้นที่เก็บข้อมูลของฉันสำหรับชั้นเรียนหลักเช่นเดียวกับชั้นเรียนที่ใช้มันและตัวแยกวิเคราะห์ตัวเลือก


9
คำตอบนี้ชัดเจนอย่างน่าอัศจรรย์และง่ายต่อการติดตาม - สำหรับ python 2.3 ถึง 2.6 สำหรับ python 2.7+ มันไม่ใช่คำตอบที่ดีที่สุดเนื่องจาก argparse เป็นส่วนหนึ่งของไลบรารี่มาตรฐานและไม่สนับสนุน optparse
matt wilkie

ในกรณีของฉันฉันต้องการโปรไฟล์แอปพลิเคชันของฉันเพื่อตรวจหาความเชื่องช้า มีอีกเครื่องมือหนึ่งที่เรียกว่า [tuna] ( github.com/nschloe/tuna ) ซึ่งอนุญาตให้ฉันสร้างโปรไฟล์แอปพลิเคชันทั้งหมดโดยเพียงเพิ่ม agrs -mcProfile -o program.profแต่ agrparcer กำลังดักจับ args เหล่านี้ฉันจะส่ง args เหล่านี้ไปยัง python exe ได้อย่างไร?
Yogeshwar

231

argparseเป็นวิธีที่จะไป นี่เป็นบทสรุปย่อของวิธีใช้:

1) เริ่มต้น

import argparse

# Instantiate the parser
parser = argparse.ArgumentParser(description='Optional app description')

2) เพิ่มอาร์กิวเมนต์

# Required positional argument
parser.add_argument('pos_arg', type=int,
                    help='A required integer positional argument')

# Optional positional argument
parser.add_argument('opt_pos_arg', type=int, nargs='?',
                    help='An optional integer positional argument')

# Optional argument
parser.add_argument('--opt_arg', type=int,
                    help='An optional integer argument')

# Switch
parser.add_argument('--switch', action='store_true',
                    help='A boolean switch')

3) แยกวิเคราะห์

args = parser.parse_args()

4) การเข้าถึง

print("Argument values:")
print(args.pos_arg)
print(args.opt_pos_arg)
print(args.opt_arg)
print(args.switch)

5) ตรวจสอบค่า

if args.pos_arg > 10:
    parser.error("pos_arg cannot be larger than 10")

การใช้

การใช้งานที่ถูกต้อง:

$ ./app 1 2 --opt_arg 3 --switch

Argument values:
1
2
3
True

อาร์กิวเมนต์ไม่ถูกต้อง:

$ ./app foo 2 --opt_arg 3 --switch
usage: convert [-h] [--opt_arg OPT_ARG] [--switch] pos_arg [opt_pos_arg]
app: error: argument pos_arg: invalid int value: 'foo'

$ ./app 11 2 --opt_arg 3
Argument values:
11
2
3
False
usage: app [-h] [--opt_arg OPT_ARG] [--switch] pos_arg [opt_pos_arg]
convert: error: pos_arg cannot be larger than 10

ช่วยเต็ม:

$ ./app -h

usage: app [-h] [--opt_arg OPT_ARG] [--switch] pos_arg [opt_pos_arg]

Optional app description

positional arguments:
  pos_arg            A required integer positional argument
  opt_pos_arg        An optional integer positional argument

optional arguments:
  -h, --help         show this help message and exit
  --opt_arg OPT_ARG  An optional integer argument
  --switch           A boolean switch

10
นี่คือรัดกุมและมีประโยชน์และนี่คือ doc อย่างเป็นทางการ (เพื่อความสะดวก): docs.python.org/3/library/argparse.html
Christophe Roussy

1
หากคุณพบว่าการโต้แย้งอย่างชัดแจ้งเกินไปให้ใช้placแทน
Nimitz14

76

ใช้ docopt

ตั้งแต่ปี 2012 เป็นเรื่องง่ายมากที่มีประสิทธิภาพและจริงๆเย็นโมดูลสำหรับอาร์กิวเมนต์แยกเรียกว่าdocopt นี่คือตัวอย่างที่นำมาจากเอกสาร:

"""Naval Fate.

Usage:
  naval_fate.py ship new <name>...
  naval_fate.py ship <name> move <x> <y> [--speed=<kn>]
  naval_fate.py ship shoot <x> <y>
  naval_fate.py mine (set|remove) <x> <y> [--moored | --drifting]
  naval_fate.py (-h | --help)
  naval_fate.py --version

Options:
  -h --help     Show this screen.
  --version     Show version.
  --speed=<kn>  Speed in knots [default: 10].
  --moored      Moored (anchored) mine.
  --drifting    Drifting mine.

"""
from docopt import docopt


if __name__ == '__main__':
    arguments = docopt(__doc__, version='Naval Fate 2.0')
    print(arguments)

ดังนั้นนี่คือมัน: โค้ด 2 บรรทัดรวมถึงสตริง doc ของคุณซึ่งเป็นสิ่งจำเป็นและคุณจะได้รับการวิเคราะห์แยกวิเคราะห์และมีอยู่ในวัตถุอาร์กิวเมนต์ของคุณ

ใช้ python-fire

ตั้งแต่ 2017 มีอีกโมดูลเย็นเรียกว่างูหลามไฟ มันสามารถสร้างส่วนต่อประสาน CLI ให้กับโค้ดของคุณเมื่อคุณทำการแยกอาร์กิวเมนต์เป็นศูนย์ นี่คือตัวอย่างง่ายๆจากเอกสารประกอบ (โปรแกรมขนาดเล็กนี้แสดงฟังก์ชันdoubleไปที่บรรทัดคำสั่ง):

import fire

class Calculator(object):

  def double(self, number):
    return 2 * number

if __name__ == '__main__':
  fire.Fire(Calculator)

จากบรรทัดคำสั่งคุณสามารถเรียกใช้:

> calculator.py double 10
20
> calculator.py double --number=15
30

4
docopt "ไม่จำเป็นต้องติดตั้ง" อย่างไร? มันเป็นโมดูลหลามดังนั้นจึงไม่จำเป็นต้องติดตั้ง 'ImportError: ไม่มีโมดูลชื่อ docopt'
คม

1
@keen ไม่ได้รวมอยู่กับงูหลาม แต่คุณไม่จำเป็นต้องติดตั้ง: "คุณเพียงแค่วางไฟล์ docopt.py ลงในโครงการของคุณ - มันมีอยู่ในตัวเอง" - github.com/docopt/docopt
ndemou

9
เรามีคำจำกัดความที่แตกต่างกันของการติดตั้ง - และฉันต้องการชี้ให้เห็นสำหรับผู้อ่านในอนาคต
คม

1
@keen ฉันได้เพิ่มข้อความ "ไม่ต้องติดตั้ง" สำหรับคนที่แชร์คำจำกัดความของคุณ :-)
ndemou

39

วิธีใหม่สะโพกคือargparseสำหรับเหล่านี้ด้วยเหตุผล argparse> optparse> getopt

update:ณ py2.7 argparseเป็นส่วนหนึ่งของไลบรารี่มาตรฐานและoptparseเลิกใช้แล้ว


ลิงก์หลักของคุณคือ 404 ดังนั้นฉันจึงแทนที่ด้วยลิงก์ไปยังคำถาม SO ที่เน้นหัวข้อเดียวกัน
Joe Holloway

28

ฉันชอบคลิกคลิกมันเป็นนามธรรมจัดการตัวเลือกและช่วยให้ "(... ) การสร้างอินเตอร์เฟซบรรทัดคำสั่งที่สวยงามในวิธีการแต่งที่มีรหัสน้อยเท่าที่จำเป็น"

นี่คือตัวอย่างการใช้งาน:

import click

@click.command()
@click.option('--count', default=1, help='Number of greetings.')
@click.option('--name', prompt='Your name',
              help='The person to greet.')
def hello(count, name):
    """Simple program that greets NAME for a total of COUNT times."""
    for x in range(count):
        click.echo('Hello %s!' % name)

if __name__ == '__main__':
    hello()

มันยังสร้างหน้าช่วยเหลือในรูปแบบอัตโนมัติ:

$ python hello.py --help
Usage: hello.py [OPTIONS]

  Simple program that greets NAME for a total of COUNT times.

Options:
  --count INTEGER  Number of greetings.
  --name TEXT      The person to greet.
  --help           Show this message and exit.

14

แทบทุกคนใช้getopt อยู่

นี่คือตัวอย่างรหัสสำหรับเอกสาร:

import getopt, sys

def main():
    try:
        opts, args = getopt.getopt(sys.argv[1:], "ho:v", ["help", "output="])
    except getopt.GetoptError:
        # print help information and exit:
        usage()
        sys.exit(2)
    output = None
    verbose = False
    for o, a in opts:
        if o == "-v":
            verbose = True
        if o in ("-h", "--help"):
            usage()
            sys.exit()
        if o in ("-o", "--output"):
            output = a

ดังนั้นในคำนี่คือวิธีการทำงาน

คุณมีตัวเลือกสองประเภท ผู้ที่ได้รับการโต้แย้งและผู้ที่เป็นเหมือนสวิตช์

sys.argvมันสวยมากchar** argvใน C เช่นเดียวกับใน C คุณข้ามองค์ประกอบแรกซึ่งเป็นชื่อของโปรแกรมของคุณและแยกอาร์กิวเมนต์เท่านั้น:sys.argv[1:]

Getopt.getopt จะแยกมันตามกฎที่คุณให้ในการโต้แย้ง

"ho:v"-ONELETTERนี่อธิบายข้อโต้แย้งสั้น: :หมายความว่า-oยอมรับอาร์กิวเมนต์หนึ่ง

ในที่สุดก็["help", "output="]อธิบายอาร์กิวเมนต์ที่มีความยาว ( --MORETHANONELETTER) =หลังจากที่การส่งออกอีกครั้งหมายถึงการส่งออกที่ยอมรับหนึ่งข้อโต้แย้ง

ผลลัพธ์คือรายการของคู่ (ตัวเลือกอาร์กิวเมนต์)

หากตัวเลือกไม่ยอมรับอาร์กิวเมนต์ใด ๆ (เช่น--helpที่นี่)argส่วนนั้นเป็นสตริงว่าง จากนั้นคุณมักจะต้องการวนซ้ำในรายการนี้และทดสอบชื่อตัวเลือกดังตัวอย่าง

ฉันหวังว่านี่จะช่วยคุณได้


6
ด้วยความไม่เห็นด้วยgetoptของ Python เวอร์ชั่นใหม่กว่าคำตอบนี้ล้าสมัยแล้ว
shuttle87

1
@ shuttle87 ในฐานะของ python3.7.2 getoptยังไม่เลิกใช้ ... แต่เอกสารระบุว่าส่วนใหญ่มีไว้สำหรับผู้ใช้ที่คุ้นเคยกับgetopt()ฟังก์ชั่นC และยอมรับว่าสำหรับผู้ใช้รายอื่นargparseอาจเป็นทางออกที่ดีกว่าช่วยให้ "เขียนรหัสน้อยลงและรับ ความช่วยเหลือและข้อความแสดงข้อผิดพลาดที่ดีขึ้น ".
Skippy le Grand Gourou

14

ใช้optparseซึ่งมาพร้อมกับไลบรารีมาตรฐาน ตัวอย่างเช่น:

#!/usr/bin/env python
import optparse

def main():
  p = optparse.OptionParser()
  p.add_option('--person', '-p', default="world")
  options, arguments = p.parse_args()
  print 'Hello %s' % options.person

if __name__ == '__main__':
  main()

ที่มา: การใช้ Python เพื่อสร้างเครื่องมือบรรทัดคำสั่ง UNIX

อย่างไรก็ตาม Python 2.7 optparse เลิกใช้แล้วดูที่: ทำไมใช้ argparse มากกว่า optparse


6

ในกรณีที่คุณอาจจำเป็นต้องใช้สิ่งนี้อาจช่วยถ้าคุณต้องการคว้าอาร์กิวเมนต์ unicode บน Win32 (2K, XP และอื่น ๆ ):


from ctypes import *

def wmain(argc, argv):
    print argc
    for i in argv:
        print i
    return 0

def startup():
    size = c_int()
    ptr = windll.shell32.CommandLineToArgvW(windll.kernel32.GetCommandLineW(), byref(size))
    ref = c_wchar_p * size.value
    raw = ref.from_address(ptr)
    args = [arg for arg in raw]
    windll.kernel32.LocalFree(ptr)
    exit(wmain(len(args), args))
startup()

ขอบคุณ. สคริปต์นี้ช่วยให้ฉันทำงานบางอย่างที่ซับซ้อนจริงๆฉันต้องทำเมื่อผ่านคำสั่งเริ่มต้นไปยัง GVim
telotortium

6

อาร์กิวเมนต์บรรทัดคำสั่งที่มีน้ำหนักเบาเป็นค่าเริ่มต้น

แม้ว่าargparseจะยอดเยี่ยมและเป็นคำตอบที่ถูกต้องสำหรับสวิตช์บรรทัดคำสั่งที่มีเอกสารครบถ้วนและคุณสมบัติขั้นสูงคุณสามารถใช้ค่าเริ่มต้นของอาร์กิวเมนต์ของฟังก์ชันเพื่อจัดการกับข้อโต้แย้งตำแหน่งที่ตรงไปตรงมาได้อย่างง่ายดาย

import sys

def get_args(name='default', first='a', second=2):
    return first, int(second)

first, second = get_args(*sys.argv)
print first, second

อาร์กิวเมนต์ 'name' รวบรวมชื่อสคริปต์และไม่ได้ใช้ ผลการทดสอบมีลักษณะดังนี้:

> ./test.py
a 2
> ./test.py A
A 2
> ./test.py A 20
A 20

สำหรับสคริปต์ง่ายๆที่ฉันต้องการค่าเริ่มต้นบางอย่างฉันพบว่ามันค่อนข้างเพียงพอ คุณอาจต้องการรวมการบีบบังคับบางประเภทในค่าส่งคืนหรือค่าบรรทัดคำสั่งทั้งหมดจะเป็นสตริง


2
เครื่องหมายคำพูดไม่ตรงกันในคำสั่ง def
historystamp

3

ฉันชอบ optparse เพื่อ getopt มันเป็นการประกาศที่ดีมาก: คุณบอกชื่อของตัวเลือกและเอฟเฟกต์ที่ควรมี (เช่นการตั้งค่าฟิลด์บูลีน) และมันจะช่วยให้คุณคืนค่าพจนานุกรมตามข้อมูลจำเพาะของคุณ

http://docs.python.org/lib/module-optparse.html


3

ฉันคิดว่าวิธีที่ดีที่สุดสำหรับโครงการขนาดใหญ่คือ optparse แต่หากคุณกำลังมองหาวิธีที่ง่ายบางทีhttp://werkzeug.pocoo.org/documentation/scriptเป็นสิ่งที่ดีสำหรับคุณ

from werkzeug import script

# actions go here
def action_foo(name=""):
    """action foo does foo"""
    pass

def action_bar(id=0, title="default title"):
    """action bar does bar"""
    pass

if __name__ == '__main__':
    script.run()

ดังนั้นโดยทั่วไปทุกฟังก์ชั่น action_ * จะถูกเปิดรับบรรทัดคำสั่งและมีข้อความช่วยเหลือที่ดีซึ่งถูกสร้างขึ้นฟรี

python foo.py 
usage: foo.py <action> [<options>]
       foo.py --help

actions:
  bar:
    action bar does bar

    --id                          integer   0
    --title                       string    default title

  foo:
    action foo does foo

    --name                        string

declarative_parserผมได้พัฒนาแพคเกจขนาดเล็กใช้สร้างข้อโต้แย้งอัตโนมัติ: แน่นอนว่าหากมีการทำงานร่วมกับ Werkzeug werkzung.scriptมันอาจจะดีกว่าที่จะให้ อย่างไรก็ตามฉันเป็นแฟนตัวยงของวิธีการดังกล่าว
krassowski

3

รหัส Argparse อาจยาวกว่ารหัสการนำไปใช้จริง!

นั่นเป็นปัญหาที่ฉันพบกับตัวเลือกการแยกวิเคราะห์ที่เป็นที่นิยมที่สุดคือถ้าพารามิเตอร์ของคุณมีค่าเพียงเล็กน้อยรหัสในการทำเอกสารจะมีขนาดใหญ่เกินกว่าประโยชน์ที่ได้รับ

ผู้มาใหม่ที่เกี่ยวข้องกับการแยกวิเคราะห์ฉาก (ฉันคิดว่า) เป็นที่โล่งอก

มันทำให้บางคนยอมรับการแลกเปลี่ยนกับ argparse แต่ใช้เอกสารแบบอินไลน์และล้อมรอบmain()ฟังก์ชั่นฟังก์ชั่นประเภท:

def main(excel_file_path: "Path to input training file.",
     excel_sheet_name:"Name of the excel sheet containing training data including columns 'Label' and 'Description'.",
     existing_model_path: "Path to an existing model to refine."=None,
     batch_size_start: "The smallest size of any minibatch."=10.,
     batch_size_stop:  "The largest size of any minibatch."=250.,
     batch_size_step:  "The step for increase in minibatch size."=1.002,
     batch_test_steps: "Flag.  If True, show minibatch steps."=False):
"Train a Spacy (http://spacy.io/) text classification model with gold document and label data until the model nears convergence (LOSS < 0.5)."

    pass # Implementation code goes here!

if __name__ == '__main__':
    import plac; plac.call(main)

จุดของข้อมูล: การใช้งาน plac อย่างประณีต (ดังแสดงในตัวอย่าง) ใช้สำหรับ Python 3.x เท่านั้นเนื่องจากใช้หมายเหตุประกอบฟังก์ชัน 3.x
barny

1

consoleargsสมควรที่จะกล่าวถึงที่นี่ มันใช้งานง่ายมาก ลองดูสิ:

from consoleargs import command

@command
def main(url, name=None):
  """
  :param url: Remote URL 
  :param name: File name
  """
  print """Downloading url '%r' into file '%r'""" % (url, name)

if __name__ == '__main__':
  main()

ตอนนี้อยู่ในคอนโซล:

% python demo.py --help
Usage: demo.py URL [OPTIONS]

URL:    Remote URL 

Options:
    --name -n   File name

% python demo.py http://www.google.com/
Downloading url ''http://www.google.com/'' into file 'None'

% python demo.py http://www.google.com/ --name=index.html
Downloading url ''http://www.google.com/'' into file ''index.html''

ฉันใช้วิธีการที่คล้ายกันในdeclarative-parserดูการหักอาร์กิวเมนต์ (พิมพ์, docstrings, kwargs)ใน docs ความแตกต่างหลัก: python3, คำใบ้ประเภท, สามารถติดตั้ง pip ได้
krassowski

1
ความมุ่งมั่นล่าสุดในปี 2012
บอริส

0

นี่คือวิธีการไม่ใช่ห้องสมุดที่ดูเหมือนจะใช้ได้สำหรับฉัน

เป้าหมายที่นี่จะสั้นกระชับแต่ละอาร์กิวเมนต์แยกวิเคราะห์โดยบรรทัดเดียว args line up สำหรับการอ่านรหัสง่ายและไม่ขึ้นอยู่กับโมดูลพิเศษใด ๆ (เฉพาะ OS + sys) เตือนเกี่ยวกับข้อโต้แย้งที่ขาดหายไปหรือไม่รู้จักอย่างสง่างาม ใช้การวนลูปแบบง่ายๆสำหรับ / range () และทำงานผ่าน python 2.x และ 3.x

แสดงว่ามีสองสถานะสลับ (-d, -v) และสองค่าควบคุมโดยข้อโต้แย้ง (-i xxx และ -o xxx)

import os,sys

def HelpAndExit():
    print("<<your help output goes here>>")
    sys.exit(1)

def Fatal(msg):
    sys.stderr.write("%s: %s\n" % (os.path.basename(sys.argv[0]), msg))
    sys.exit(1)

def NextArg(i):
    '''Return the next command line argument (if there is one)'''
    if ((i+1) >= len(sys.argv)):
        Fatal("'%s' expected an argument" % sys.argv[i])
    return(1, sys.argv[i+1])

### MAIN
if __name__=='__main__':

    verbose = 0
    debug   = 0
    infile  = "infile"
    outfile = "outfile"

    # Parse command line
    skip = 0
    for i in range(1, len(sys.argv)):
        if not skip:
            if   sys.argv[i][:2] == "-d": debug ^= 1
            elif sys.argv[i][:2] == "-v": verbose ^= 1
            elif sys.argv[i][:2] == "-i": (skip,infile)  = NextArg(i)
            elif sys.argv[i][:2] == "-o": (skip,outfile) = NextArg(i)
            elif sys.argv[i][:2] == "-h": HelpAndExit()
            elif sys.argv[i][:1] == "-":  Fatal("'%s' unknown argument" % sys.argv[i])
            else:                         Fatal("'%s' unexpected" % sys.argv[i])
        else: skip = 0

    print("%d,%d,%s,%s" % (debug,verbose,infile,outfile))

เป้าหมายของ NextArg () คือการส่งคืนอาร์กิวเมนต์ถัดไปขณะตรวจสอบข้อมูลที่หายไปและ 'ข้าม' ข้ามลูปเมื่อใช้ NextArg () เพื่อรักษาสถานะการแยกวิเคราะห์ลงในหนึ่ง liners


0

ฉันขยายวิธีการของ Erco เพื่ออนุญาตให้มีการขัดแย้งกับตำแหน่งที่ต้องการและสำหรับข้อโต้แย้งเพิ่มเติม สิ่งเหล่านี้ควรอยู่หน้าอาร์กิวเมนต์ -d, -v ฯลฯ

อาร์กิวเมนต์ตำแหน่งและตัวเลือกสามารถเรียกคืนได้ด้วย PosArg (i) และ OptArg (i, default) ตามลำดับ เมื่อพบอาร์กิวเมนต์ที่เป็นทางเลือกตำแหน่งเริ่มต้นของการค้นหาตัวเลือก (เช่น -i) จะถูกย้าย 1 ไปข้างหน้าเพื่อหลีกเลี่ยงการทำให้เกิดอันตรายที่ไม่คาดคิด

import os,sys


def HelpAndExit():
    print("<<your help output goes here>>")
    sys.exit(1)

def Fatal(msg):
    sys.stderr.write("%s: %s\n" % (os.path.basename(sys.argv[0]), msg))
    sys.exit(1)

def NextArg(i):
    '''Return the next command line argument (if there is one)'''
    if ((i+1) >= len(sys.argv)):
        Fatal("'%s' expected an argument" % sys.argv[i])
    return(1, sys.argv[i+1])

def PosArg(i):
    '''Return positional argument'''
    if i >= len(sys.argv):
        Fatal("'%s' expected an argument" % sys.argv[i])
    return sys.argv[i]

def OptArg(i, default):
    '''Return optional argument (if there is one)'''
    if i >= len(sys.argv):
        Fatal("'%s' expected an argument" % sys.argv[i])
    if sys.argv[i][:1] != '-':
        return True, sys.argv[i]
    else:
        return False, default


### MAIN
if __name__=='__main__':

    verbose = 0
    debug   = 0
    infile  = "infile"
    outfile = "outfile"
    options_start = 3

    # --- Parse two positional parameters ---
    n1 = int(PosArg(1))
    n2 = int(PosArg(2))

    # --- Parse an optional parameters ---
    present, a3 = OptArg(3,50)
    n3 = int(a3)
    options_start += int(present)

    # --- Parse rest of command line ---
    skip = 0
    for i in range(options_start, len(sys.argv)):
        if not skip:
            if   sys.argv[i][:2] == "-d": debug ^= 1
            elif sys.argv[i][:2] == "-v": verbose ^= 1
            elif sys.argv[i][:2] == "-i": (skip,infile)  = NextArg(i)
            elif sys.argv[i][:2] == "-o": (skip,outfile) = NextArg(i)
            elif sys.argv[i][:2] == "-h": HelpAndExit()
            elif sys.argv[i][:1] == "-":  Fatal("'%s' unknown argument" % sys.argv[i])
            else:                         Fatal("'%s' unexpected" % sys.argv[i])
        else: skip = 0

    print("Number 1 = %d" % n1)
    print("Number 2 = %d" % n2)
    print("Number 3 = %d" % n3)
    print("Debug    = %d" % debug)
    print("verbose  = %d" % verbose)
    print("infile   = %s" % infile)
    print("outfile  = %s" % outfile) 
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.