Làm thế nào để đọc / xử lý các đối số dòng lệnh?


623

5
Sử dụng docopt (xem câu trả lời của @ ralbatross tại stackoverflow.com/a/14790373/116891 ). Tôi đã thử mọi cách và thực sự, docopt là cách duy nhất tôi sẽ sử dụng trong tương lai.
Pat

2
Tôi không nghĩ có một cách tốt nhất. argparse là tiêu chuẩn và tính năng. docopt rất thanh lịch nhưng không có trong thư viện tiêu chuẩn. Để sử dụng rất nhẹ, bạn có thể đặt các giá trị mặc định của hàm xử lý mặc định đối số dòng comand cho bạn .
Simon Hibbs

Câu trả lời:


456

Giải pháp chính tắc trong thư viện chuẩn là argparse( docs ):

Đây là một ví dụ:

from argparse import ArgumentParser

parser = ArgumentParser()
parser.add_argument("-f", "--file", dest="filename",
                    help="write report to FILE", metavar="FILE")
parser.add_argument("-q", "--quiet",
                    action="store_false", dest="verbose", default=True,
                    help="don't print status messages to stdout")

args = parser.parse_args()

argparse hỗ trợ (trong số những thứ khác):

  • Nhiều lựa chọn theo thứ tự bất kỳ.
  • Tùy chọn ngắn và dài.
  • Giá trị mặc định.
  • Tạo một thông báo trợ giúp sử dụng.

27
Vâng, đây là những điều tốt nhất. Vì chúng là một phần của thư viện chuẩn, bạn có thể chắc chắn rằng chúng sẽ có sẵn và chúng rất dễ sử dụng. optparse nói riêng là mạnh mẽ và dễ dàng.
Barry Wark

4
optparse là một trong những tốt nhất; getopt đã cũ và thực sự nên được coi là không dùng nữa.
jemfinch

12
tại thời điểm này (12/2011), argparse hiện được coi là một lựa chọn tốt hơn optparse, đúng không?
oob

54
Tài liệu Python đề xuất việc sử dụng argparse thay vì optparse.
earthmeLon

7
optparsekhông được chấp nhận, người hỏi của câu hỏi không còn là thành viên trong ngăn xếp chồng và đây là câu trả lời được chấp nhận cho câu hỏi rất dễ thấy - thay vào đó, hãy xem xét viết lại hoàn toàn mã ví dụ của bạn để sử dụng stdlib argparse.
wim

548
import sys

print("\n".join(sys.argv))

sys.argv là một danh sách chứa tất cả các đối số được truyền cho tập lệnh trên dòng lệnh.

Về cơ bản,

import sys
print(sys.argv[1:])

83
Đối với những thứ thực sự đơn giản, đây là cách để đi, mặc dù bạn có thể chỉ muốn sử dụng sys.argv[1:](tránh tên tập lệnh).
Xiong Chiamiov

128

Chỉ cần đi xung quanh việc truyền giáo cho argparse , điều này tốt hơn cho những lý do này .. về cơ bản:

(được sao chép từ liên kết)

  • mô-đun argparse có thể xử lý các đối số tùy chọn và vị trí, trong khi optparse chỉ có thể xử lý các đối số tùy chọn

  • argparse không giáo điều về giao diện dòng lệnh của bạn sẽ trông như thế nào - các tùy chọn như -file hoặc / file được hỗ trợ, như các tùy chọn bắt buộc. Optparse từ chối hỗ trợ các tính năng này, ưu tiên độ tinh khiết hơn tính thực tế

  • argparse tạo ra nhiều thông báo sử dụng thông tin hơn, bao gồm cả việc sử dụng dòng lệnh được xác định từ các đối số của bạn và thông báo trợ giúp cho cả đối số vị trí và tùy chọn. Mô-đun optparse yêu cầu bạn viết chuỗi sử dụng của riêng bạn và không có cách nào để hiển thị trợ giúp cho các đối số vị trí.

  • argparse hỗ trợ hành động tiêu thụ một số lượng lớn các đối số dòng lệnh, trong khi optparse yêu cầu phải biết trước số lượng chính xác của các đối số (ví dụ 1, 2 hoặc 3)

  • argparse hỗ trợ các trình phân tích cú pháp gửi đến các lệnh phụ, trong khi optparse yêu cầu thiết lập allow_interspersed_argsvà thực hiện việc gửi trình phân tích cú pháp theo cách thủ công

Và sở thích cá nhân của tôi:

  • argparse cho phép các tham số loại và hành động add_argument() được chỉ định bằng các hàm gọi đơn giản, trong khi optparse yêu cầu hack các thuộc tính lớp như STORE_ACTIONShoặc CHECK_METHODSđể kiểm tra đối số thích hợp

27
Đây hiện là một phần của Python tiêu chuẩn kể từ 2.7 và 3.2 :)
jpswain

"Đối số tùy chọn" là gì? Bạn nói rằng họ đang ở trong optparse. Tôi nghĩ rằng chúng là những đối số có thể được cung cấp hoặc không được cung cấp, nhưng bạn nói rằng chúng ở trạng thái quang trong khi tiếp tục nói rằng "optparse yêu cầu phải biết trước số lượng đối số chính xác". Vì vậy, định nghĩa của bạn về "đối số tùy chọn" khác với những gì tôi nghĩ, hoặc câu trả lời của bạn không nhất quán với chính nó.
ArtOfWarfare

1
Chỉ cần một nắm chặt: tài liệu argparse cũng điên rồ, phức tạp điên cuồng. Bạn không thể nhận được một câu trả lời đơn giản cho "làm cách nào để tạo một đối số dòng lệnh lấy một giá trị duy nhất và làm thế nào để tôi truy cập giá trị đó." </ gripe>
osman

2
@osman Hướng dẫn nhẹ nhàng này về argparse có thể giúp ...
cuộc sống

2
@ArtOfWarfare "đối số tùy chọn" trong ngữ cảnh này có lẽ có nghĩa là các đối số được chỉ định bằng các đối số giống như tùy chọn , -fhoặc --footrong khi "số lượng đối số chính xác được biết trước" có lẽ có nghĩa là các đối số vị trí được đưa ra mà không có bất kỳ cờ tùy chọn nào trước đó.
mtraceur

67

Ngoài ra còn có argparsemô-đun stdlib (một "sự thay đổi" trên optparsemô-đun của stdlib ). Ví dụ từ phần giới thiệu về argparse :

# script.py
import argparse

if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument(
        'integers', metavar='int', type=int, choices=range(10),
         nargs='+', help='an integer in the range 0..9')
    parser.add_argument(
        '--sum', dest='accumulate', action='store_const', const=sum,
        default=max, help='sum the integers (default: find the max)')

    args = parser.parse_args()
    print(args.accumulate(args.integers))

Sử dụng:

$ script.py 1 2 3 4
4

$ script.py --sum 1 2 3 4
10

1
nó chỉ là một bản sao và dán
blitu12345

3
@ blitu12345 tại thời điểm công bố câu trả lời của tôi, không có câu trả lời nào khác đề cập đến argparse dưới bất kỳ hình thức nào. Bản thân mô-đun không có trong stdlib¶ Bạn có gì chống lại các ví dụ mã từ tài liệu? Tại sao bạn nghĩ cần phải đưa ra các ví dụ của riêng bạn thay vì các ví dụ được cung cấp bởi tác giả của mô-đun? Và tôi không thích câu trả lời chỉ liên kết (Tôi không đơn độc).
jfs

1
Mọi người đến đây đã có ý tưởng về tài liệu này và sẽ chỉ ở đây để giải thích thêm về chủ đề này. Đây là trường hợp của tôi nhưng những gì tôi thực sự tìm thấy ở đây là một bản sao và dán từ tài liệu gốc.Peace!
blitu12345

2
"Những người đến đây đã có một ý tưởng trong tài liệu" - tôi rất nghi ngờ giả định đó. bằng cách nào đó
sjas

49

Một cách để làm điều đó là sử dụng sys.argv. Điều này sẽ in tên tập lệnh làm đối số đầu tiên và tất cả các tham số khác mà bạn truyền cho nó.

import sys

for arg in sys.argv:
    print arg

49

Các docopt thư viện thực sự là slick. Nó xây dựng một đối số dict từ chuỗi sử dụng cho ứng dụng của bạn.

Ví dụ: từ docopt readme:

"""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)

4
Điều này đã nhanh chóng trở thành cách yêu thích của tôi để đi. Đó là phân tích cú pháp chuỗi vì vậy nó dễ vỡ, nhưng nó dễ vỡ tất cả ở một nơi và bạn có thể xem trước logic của mình tại try.docopt.org . Các đối số tùy chọn và loại trừ lẫn nhau được thực hiện theo cách thực sự thanh lịch.
gvoysey

4
Tôi tuyệt vọng khi thấy phần còn lại của mã cho naval_fate.py
John Lawrence Aspden

48

Nếu bạn cần một cái gì đó nhanh chóng và không linh hoạt

chính:

import sys

first_name = sys.argv[1]
last_name = sys.argv[2]
print("Hello " + first_name + " " + last_name)

Sau đó chạy python main.py James Smith

để tạo ra đầu ra sau:

Xin chào James Smith


Một cách sử dụng thực tế hơn sẽ được python main.py "James Smith"đưa James Smithvào sys.argv[1]và tạo ra IndexErrorkhi bạn cố gắng sử dụng không tồn tại sys.argv[2]. Hành vi trích dẫn sẽ phần nào phụ thuộc vào nền tảng và shell mà bạn chạy Python từ đó.
tripleee

10
Tôi không đồng ý rằng việc sử dụng của tôi là ít thực tế. Giả sử chương trình của bạn cần biết tên và họ chính xác của một người để chạy tập lệnh trong một doanh nghiệp nơi mọi người có thể có nhiều tên và họ? Nếu James Smith có Joseph làm họ hoặc tên phụ, làm thế nào để phân biệt giữa Joseph là tên phụ hay họ nếu bạn chỉ làm python main.py "James Joseph Smith"thế? Nếu bạn quan tâm đến chỉ số ngoài giới hạn, bạn có thể thêm một kiểm tra cho số lượng đối số được cung cấp. Ít thực tế hơn hay không, ví dụ của tôi cho thấy cách xử lý nhiều đối số.
Kent Munthe Caspersen

1
Tất cả các câu trả lời khác là cho âm mưu hạ cánh mặt trăng. Tôi chỉ đơn giản là sử dụng gmail-trash-msg.py MessageID. Câu trả lời này là thẳng về phía trước để kiểm tra MessageIDtham số đã được thông qua sys.argv[1].
WinEunuuchs2Unix

26
#set default args as -h , if no args:
if len(sys.argv) == 1: sys.argv[1:] = ["-h"]

19

Tôi sử dụng optparse cho mình, nhưng thực sự thích hướng mà Simon Willison đang thực hiện với thư viện optfunc được giới thiệu gần đây của anh ấy . Nó hoạt động bằng cách:

"hướng nội một định nghĩa hàm (bao gồm các đối số và giá trị mặc định của chúng) và sử dụng nó để xây dựng trình phân tích cú pháp đối số dòng lệnh."

Vì vậy, ví dụ, định nghĩa hàm này:

def geocode(s, api_key='', geocoder='google', list_geocoders=False):

được chuyển thành văn bản trợ giúp optparse này:

    Options:
      -h, --help            show this help message and exit
      -l, --list-geocoders
      -a API_KEY, --api-key=API_KEY
      -g GEOCODER, --geocoder=GEOCODER

8

Tôi thích getopt từ stdlib, vd:

try:
    opts, args = getopt.getopt(sys.argv[1:], 'h', ['help'])
except getopt.GetoptError, err: 
    usage(err)

for opt, arg in opts:
    if opt in ('-h', '--help'): 
        usage()

if len(args) != 1:
    usage("specify thing...")

Gần đây tôi đã gói một cái gì đó tương tự như thế này để làm cho mọi thứ bớt dài dòng hơn (ví dụ: làm cho "-h" ẩn).


8

Nhấp chuột của Pocoo trực quan hơn, yêu cầu ít nồi hơi hơn và ít nhất là mạnh mẽ như argparse.

Điểm yếu duy nhất tôi gặp phải cho đến nay là bạn không thể thực hiện nhiều tùy chỉnh để trợ giúp các trang, nhưng đó thường không phải là một yêu cầu và docopt có vẻ như là sự lựa chọn rõ ràng khi có.


7

Như bạn có thể thấy optparse "Mô-đun optparse không được dùng nữa và sẽ không được phát triển thêm nữa, sự phát triển sẽ tiếp tục với mô-đun argparse ."


5
import argparse

parser = argparse.ArgumentParser(description='Process some integers.')
parser.add_argument('integers', metavar='N', type=int, nargs='+',
                   help='an integer for the accumulator')
parser.add_argument('--sum', dest='accumulate', action='store_const',
                   const=sum, default=max,
                   help='sum the integers (default: find the max)')

args = parser.parse_args()
print(args.accumulate(args.integers))

Assuming the Python code above is saved into a file called prog.py
$ python prog.py -h

Ref-link: https://docs.python.org/3.3/library/argparse.html

4

Bạn có thể quan tâm đến một mô-đun Python nhỏ mà tôi đã viết để giúp xử lý các đối số dòng lệnh dễ dàng hơn (nguồn mở và miễn phí sử dụng) - Commando


1
Đã có một mô-đun phân tích dòng lệnh khác có tên Commando: github.com/lakshmivyas/commando . Nó kết thúc argparse bằng cách sử dụng trang trí.
Roberto Bonvallet

1
tái tạo con trăn và bánh xe
Derek

4

Tôi khuyên bạn nên nhìn vào docopt như một sự thay thế đơn giản cho những người khác.

docopt là một dự án mới hoạt động bằng cách phân tích thông điệp sử dụng - trợ giúp của bạn thay vì yêu cầu bạn tự thực hiện mọi thứ. Bạn chỉ cần đặt thông điệp sử dụng của bạn ở định dạng POSIX.


4

Một lựa chọn khác là argh . Nó được xây dựng trên argparse và cho phép bạn viết những thứ như:

import argh

# declaring:

def echo(text):
    "Returns given word as is."
    return text

def greet(name, greeting='Hello'):
    "Greets the user with given name. The greeting is customizable."
    return greeting + ', ' + name

# assembling:

parser = argh.ArghParser()
parser.add_commands([echo, greet])

# dispatching:

if __name__ == '__main__':
    parser.dispatch()

Nó sẽ tự động tạo trợ giúp, v.v. và bạn có thể sử dụng các trình trang trí để cung cấp hướng dẫn thêm về cách hoạt động của phân tích cú pháp.


Đây là giải pháp tốt nhất. Sử dụng arghdễ dàng hơn so với các lib khác hoặc sử dụng sys.
Juanjo Salvador

Tôi muốn thích arghnhưng nó không đặc biệt phù hợp với các tình huống trong đó mong muốn tối đa của bạn là không có lệnh với các tiểu ban.
tripleee

1
@tripleee YMMV, nhưng tôi thấy rằng đây là một khiếm khuyết trong tài liệu hơn là trong chính thư viện. Có vẻ hoàn toàn khả thi khi def frobnicate_spleches(...)xác định một chức năng thực hiện bất kỳ tập lệnh nào của bạn, sau đó thực hiện if __name__ == '__main__': argh.dispatch_command(frobnicate_spleches)ở cuối tệp.
hủy hoại thông tư

0

Giải pháp của tôi là entrypoint2 . Thí dụ:

from entrypoint2 import entrypoint
@entrypoint
def add(file, quiet=True): 
    ''' This function writes report.

    :param file: write report to FILE
    :param quiet: don't print status messages to stdout
    '''
    print file,quiet

văn bản trợ giúp:

usage: report.py [-h] [-q] [--debug] file

This function writes report.

positional arguments:
  file         write report to FILE

optional arguments:
  -h, --help   show this help message and exit
  -q, --quiet  don't print status messages to stdout
  --debug      set logging level to DEBUG
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.