Bagaimana cara membaca / memproses argumen baris perintah?

624

Saya awalnya seorang programmer C. Saya telah melihat banyak trik dan "retasan" untuk membaca berbagai argumen.

Apa sajakah cara programmer Python dapat melakukan ini?

Terkait

martineau
sumber
5
Gunakan docopt (lihat jawaban @ ralbatross di stackoverflow.com/a/14790373/116891 ). Saya sudah mencoba segala cara lain dan, sungguh, docopt adalah satu-satunya yang akan saya gunakan untuk maju.
Pat
2
Saya tidak berpikir ada satu cara terbaik. argparse adalah standar dan fitur. docopt sangat elegan tetapi tidak di perpustakaan standar. Untuk penggunaan ringan yang sangat mudah, Anda dapat membuat nilai default fungsi menangani argumen baris perintah standar untuk Anda .
Simon Hibbs

Jawaban:

457

Solusi kanonik di perpustakaan standar adalah argparse( dokumen ):

Berikut ini sebuah contoh:

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 mendukung (antara lain):

  • Banyak pilihan dalam urutan apa pun.
  • Opsi pendek dan panjang.
  • Nilai dasar.
  • Pembuatan pesan bantuan penggunaan.
Ayman Hourieh
sumber
27
Ya, ini yang terbaik. Karena mereka adalah bagian dari pustaka standar, Anda dapat yakin itu tersedia dan mudah digunakan. Optparse khususnya kuat dan mudah.
Barry Wark
4
optparse adalah salah satu yang terbaik; getopt sudah tua dan benar-benar harus dianggap usang.
jemfinch
12
pada titik ini (12/2011), argparse sekarang dianggap sebagai opsi yang lebih baik daripada optparse, benar?
oob
54
Dokumentasi Python menyarankan penggunaan argparse bukan optparse .
earthmeLon
7
Karena optparsesudah usang, penanya pertanyaan tidak lagi menjadi anggota di stack overflow, dan ini adalah jawaban yang diterima pada pertanyaan yang sangat terlihat - harap pertimbangkan untuk sepenuhnya menulis ulang kode contoh Anda untuk menggunakan stdlib argparsesebagai gantinya.
wim
548
import sys

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

sys.argv adalah daftar yang berisi semua argumen yang diteruskan ke skrip pada baris perintah.

Pada dasarnya,

import sys
print(sys.argv[1:])
John Slavick
sumber
83
Untuk hal-hal yang sangat sederhana, ini adalah cara untuk melakukannya, walaupun Anda mungkin hanya ingin menggunakan sys.argv[1:](menghindari nama skrip).
Xiong Chiamiov
128

Hanya berkeliling evangelisasi untuk argparse yang lebih baik karena alasan ini .. pada dasarnya:

(disalin dari tautan)

  • modul argparse dapat menangani argumen posisi dan opsional, sementara optparse hanya dapat menangani argumen opsional

  • argparse tidak dogmatis tentang tampilan antarmuka baris perintah Anda - opsi seperti -file atau / file didukung, seperti opsi yang diperlukan. Optparse menolak untuk mendukung fitur-fitur ini, lebih memilih kemurnian daripada kepraktisan

  • argparse menghasilkan pesan penggunaan yang lebih informatif, termasuk penggunaan baris perintah yang ditentukan dari argumen Anda, dan pesan bantuan untuk argumen posisional dan opsional. Modul optparse mengharuskan Anda untuk menulis string penggunaan Anda sendiri, dan tidak memiliki cara untuk menampilkan bantuan untuk argumen posisi.

  • argparse mendukung tindakan yang menggunakan sejumlah variabel argumen baris perintah, sementara optparse mengharuskan jumlah argumen yang tepat (misalnya 1, 2, atau 3) diketahui terlebih dahulu

  • argparse mendukung parser yang mengirim ke sub-perintah, sedangkan optparse memerlukan pengaturan allow_interspersed_argsdan melakukan pengiriman parser secara manual

Dan favorit pribadi saya:

  • argparse memungkinkan jenis dan parameter tindakan untuk add_argument() ditentukan dengan callable sederhana, sementara optparse membutuhkan atribut kelas peretasan seperti STORE_ACTIONSatau CHECK_METHODSuntuk mendapatkan pemeriksaan argumen
Silfheed
sumber
27
Ini sekarang bagian dari Python standar pada 2.7 dan 3.2 :)
jpswain
Apa itu "argumen opsional"? Anda mengatakan mereka berada di optparse. Saya pikir mereka adalah argumen yang mungkin atau mungkin tidak disediakan, tetapi Anda mengatakan mereka dalam optparse sambil mengatakan bahwa "optparse mengharuskan jumlah argumen yang tepat diketahui sebelumnya". Jadi definisi Anda tentang "argumen opsional" berbeda dari apa yang saya pikirkan, atau jawaban Anda tidak konsisten dengan dirinya sendiri.
ArtOfWarfare
1
Hanya keluhan: dokumentasi argparse juga gila-gilaan, sangat rumit. Anda tidak bisa mendapatkan jawaban sederhana untuk "bagaimana cara membuat argumen baris perintah menerima satu nilai, dan bagaimana cara mengakses nilai itu." </gripe>
osman
2
@ Eman tutorial lembut argparse ini mungkin membantu ...
lifebalance
2
@ArtOfWarfare "argumen opsional" dalam konteks ini mungkin berarti argumen yang ditentukan dengan argumen opsi-suka seperti -fatau --foo, sementara "jumlah persis argumen yang diketahui sebelumnya" mungkin berarti argumen posisional yang diberikan tanpa bendera opsi sebelumnya.
mtraceur
67

Ada juga argparsemodul stdlib ("perbaikan" pada optparsemodul stdlib ). Contoh dari pengantar 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))

Pemakaian:

$ script.py 1 2 3 4
4

$ script.py --sum 1 2 3 4
10
jfs
sumber
1
ini hanya salin dan tempel
blitu12345
3
@ blitu12345 pada saat publikasi jawaban saya tidak ada jawaban lain yang menyebutkan argparse dengan cara apa pun. Modul itu sendiri tidak ada di stdlib¶ Apa yang Anda miliki terhadap contoh kode dari dokumentasi? Menurut Anda mengapa perlu memberikan contoh Anda sendiri dan bukan contoh yang diberikan oleh penulis modul? Dan saya tidak suka jawaban tautan saja (saya tidak sendirian).
jfs
1
Orang-orang yang datang ke sini sudah memiliki ide apa dalam dokumentasi dan akan berada di sini hanya untuk izin lebih lanjut tentang topik tersebut. Sama halnya dengan saya, tetapi yang saya temukan di sini adalah salinan dan rekat dari dokumen asli.
blitu12345
2
"Orang-orang yang datang ke sini sudah punya ide apa dalam dokumentasi" - Saya sangat meragukan asumsi itu. entah bagaimana.
sjas
49

Salah satu cara untuk melakukannya adalah menggunakan sys.argv. Ini akan mencetak nama skrip sebagai argumen pertama dan semua parameter lain yang Anda berikan.

import sys

for arg in sys.argv:
    print arg
JPCosta
sumber
49

The docopt perpustakaan benar-benar licin. Itu membangun dict argumen dari string penggunaan untuk aplikasi Anda.

Misalnya dari 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)
ralbatross
sumber
4
Ini dengan cepat menjadi cara favorit saya untuk pergi. Ini string parsing sehingga agak rapuh, tapi rapuh semua di satu tempat dan Anda dapat melihat pratinjau logika Anda di try.docopt.org . Argumen opsional dan saling eksklusif dilakukan dengan cara yang sangat elegan.
gvoysey
4
Saya sangat ingin melihat sisa kode untuk naval_fate.py
John Lawrence Aspden
48

Jika Anda membutuhkan sesuatu yang cepat dan tidak terlalu fleksibel

main.py:

import sys

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

Lalu lari python main.py James Smith

untuk menghasilkan output berikut:

Halo James Smith

Kent Munthe Caspersen
sumber
Sebuah penggunaan yang lebih realistis akan python main.py "James Smith"yang menempatkan James Smithdi sys.argv[1]dan menghasilkan IndexErrorketika Anda mencoba untuk menggunakan tidak ada yang sys.argv[2]. Perilaku mengutip agak tergantung pada platform dan shell mana Anda menjalankan Python.
tripleee
10
Saya tidak setuju bahwa penggunaan saya kurang realistis. Berpura-pura bahwa program Anda perlu mengetahui nama depan dan belakang seseorang yang tepat untuk menjalankan skrip dalam bisnis di mana orang dapat memiliki beberapa nama depan dan belakang? Jika James Smith memiliki Joseph sebagai nama depan atau belakang tambahan, bagaimana membedakan antara apakah Joseph adalah nama depan atau belakang ekstra jika Anda hanya melakukannya python main.py "James Joseph Smith"? Jika Anda khawatir dengan indeks di luar batas, Anda dapat menambahkan tanda centang untuk jumlah argumen yang disediakan. Kurang realistis atau tidak, contoh saya menunjukkan bagaimana menangani beberapa argumen.
Kent Munthe Caspersen
1
Semua jawaban lainnya adalah untuk merencanakan misi pendaratan di bulan. Saya hanya menggunakan gmail-trash-msg.py MessageID. Jawaban ini langsung ke depan untuk menguji MessageIDparameter telah diteruskan sys.argv[1].
WinEunuuchs2Unix
26
#set default args as -h , if no args:
if len(sys.argv) == 1: sys.argv[1:] = ["-h"]
whi
sumber
19

Saya menggunakan optparse sendiri, tetapi sangat suka arah yang diambil Simon Willison dengan perpustakaan optfunc yang baru diperkenalkannya . Ini bekerja dengan:

+ msgstr "mengintrospeksi definisi fungsi (termasuk argumennya dan nilai defaultnya) dan menggunakannya untuk membuat parser argumen baris perintah."

Jadi, misalnya, definisi fungsi ini:

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

diubah menjadi teks bantuan optparse ini:

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

Saya suka getopt dari stdlib, mis:

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

Akhir-akhir ini saya telah membungkus sesuatu yang serupa dengan ini untuk membuat hal-hal yang kurang verbose (misalnya; membuat "-h" tersirat).

Peter Ericson
sumber
8

Pocoo ini klik lebih intuitif, memerlukan lebih sedikit boilerplate, dan setidaknya sekuat argparse.

Satu-satunya kelemahan yang saya temui sejauh ini adalah bahwa Anda tidak dapat melakukan banyak penyesuaian untuk membantu halaman, tetapi itu biasanya bukan keharusan dan mendiagnosis tampaknya merupakan pilihan yang jelas ketika itu.

Ryne Everett
sumber
7

Seperti yang Anda lihat di optparse "Modul optparse tidak digunakan lagi dan tidak akan dikembangkan lebih lanjut; pengembangan akan dilanjutkan dengan modul argparse ."

tverrbjelke
sumber
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
JON
sumber
4

Anda mungkin tertarik pada modul Python kecil yang saya tulis untuk membuat penanganan argumen baris perintah menjadi lebih mudah (open source dan bebas digunakan) - Commando

Mufasa
sumber
1
Sudah ada modul parsing baris perintah lainnya bernama Commando: github.com/lakshmivyas/commando . Ini membungkus argparse dengan menggunakan dekorator.
Roberto Bonvallet
1
penemuan ular piton dan roda
Derek
4

Saya sarankan melihat docopt sebagai alternatif sederhana untuk yang lain ini.

docopt adalah proyek baru yang bekerja dengan mem-parsing pesan penggunaan --help Anda daripada mengharuskan Anda untuk mengimplementasikan semuanya sendiri. Anda hanya perlu meletakkan pesan penggunaan Anda dalam format POSIX.

David C. Bishop
sumber
4

Namun pilihan lain adalah argh . Itu dibangun berdasarkan argparse, dan memungkinkan Anda menulis hal-hal seperti:

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

Ini akan secara otomatis menghasilkan bantuan dan sebagainya, dan Anda dapat menggunakan dekorator untuk memberikan panduan tambahan tentang bagaimana arg-parsing seharusnya bekerja.

kehancuran melingkar
sumber
Ini solusi terbaik. Menggunakan arghlebih mudah daripada lib lain atau menggunakan sys.
Juanjo Salvador
Saya ingin suka arghtetapi itu tidak terlalu cocok untuk skenario di mana keinginan Anda yang terbaik adalah untuk tidak memiliki perintah dengan sub-perintah.
tripleee
1
@ tripleee YMMV, tapi saya menemukan bahwa ini lebih merupakan cacat dalam dokumentasi daripada di perpustakaan itu sendiri. Tampaknya layak untuk def frobnicate_spleches(...)mendefinisikan fungsi yang melakukan apa pun yang dilakukan skrip Anda, lalu lakukan if __name__ == '__main__': argh.dispatch_command(frobnicate_spleches)di akhir file.
kehancuran melingkar
0

Solusi saya adalah entrypoint2 . Contoh:

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

teks bantuan:

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
ponty
sumber