Come leggere / elaborare gli argomenti della riga di comando?


624

5
Usa docopt (vedi @ risposta di ralbatross a stackoverflow.com/a/14790373/116891 ). Ho provato in tutti gli altri modi e, davvero, docopt è l'unico che userò in futuro.
Pat

2
Non penso che ci sia un solo modo migliore. argparse è standard e ricco di funzionalità. docopt è molto elegante ma non nella libreria standard. Per un utilizzo molto semplice e leggero, è possibile fare in modo che i valori predefiniti delle funzioni gestiscano le impostazioni predefinite degli argomenti della riga di comando .
Simon Hibbs,

Risposte:


457

La soluzione canonica nella libreria standard è argparse( docs ):

Ecco un esempio:

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 supporta (tra le altre cose):

  • Molteplici opzioni in qualsiasi ordine.
  • Opzioni corte e lunghe.
  • Valori standard.
  • Generazione di un messaggio di aiuto per l'utilizzo.

27
Sì, questi sono i migliori. Dal momento che fanno parte della libreria standard, puoi essere sicuro che saranno disponibili e facili da usare. optparse in particolare è potente e facile.
Barry Wark,

4
optparse è uno dei migliori; getopt è vecchio e dovrebbe essere considerato deprecato.
jemfinch,

12
a questo punto (12/2011), argparse è ora considerato un'opzione migliore di optparse, giusto?
oob,

54
La documentazione di Python suggerisce l'uso di argparse invece di optparse.
earthmeLon

7
Dato che optparseè deprecato, chi pone la domanda non è più un membro in overflow dello stack, e questa è la risposta accettata su una domanda altamente visibile - considera invece di riscrivere completamente il tuo codice di esempio per usare stdlib argparse.
mercoledì

548
import sys

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

sys.argv è un elenco che contiene tutti gli argomenti passati allo script dalla riga di comando.

Fondamentalmente,

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

83
Per cose davvero semplici, questa è la strada da percorrere, anche se probabilmente vuoi solo usare sys.argv[1:](evita il nome dello script).
Xiong Chiamiov,

128

Basta andare in giro per evangelizzare per argparse, il che è meglio per questi motivi ... essenzialmente:

(copiato dal link)

  • Il modulo argparse può gestire argomenti posizionali e opzionali, mentre optparse può gestire solo argomenti opzionali

  • argparse non è dogmatico su come dovrebbe apparire l'interfaccia della riga di comando: sono supportate opzioni come -file o / file, così come le opzioni richieste. Optparse rifiuta di supportare queste funzionalità, preferendo la purezza alla praticità

  • argparse produce messaggi di utilizzo più informativi, incluso l'uso della riga di comando determinato dai tuoi argomenti, e aiuta i messaggi per argomenti sia posizionali che opzionali. Il modulo optparse richiede di scrivere la propria stringa di utilizzo e non ha modo di visualizzare la guida per gli argomenti posizionali.

  • argparse supporta azioni che consumano un numero variabile di argomenti della riga di comando, mentre optparse richiede che il numero esatto di argomenti (ad es. 1, 2 o 3) sia noto in anticipo

  • argparse supporta i parser che inviano ai sotto-comandi, mentre optparse richiede l'impostazione allow_interspersed_argse l'esecuzione manuale del parser

E il mio preferito personale:

  • argparse consente di specificare i parametri di tipo e azione add_argument() con semplici callable, mentre optparse richiede l'attribuzione di attributi di classe come STORE_ACTIONSo CHECK_METHODSper ottenere il corretto controllo degli argomenti

27
Questo fa ora parte dello standard Python a partire da 2.7 e 3.2 :)
jpswain,

Cosa sono gli "argomenti opzionali"? Dici che sono in optparse. Ho pensato che fossero argomenti che possono o meno essere forniti, ma hai detto che sono in optparse mentre continui dicendo che "optparse richiede che il numero esatto di argomenti sia conosciuto in anticipo". Quindi, o la tua definizione di "argomento opzionale" differisce da quello che pensavo, o la tua risposta è incompatibile con se stessa.
ArtOfWarfare il

1
Solo un inconveniente: la documentazione argparse è anche follemente, follemente complicata. Non è possibile ottenere una risposta semplice per "come posso fare in modo che un argomento della riga di comando prenda un singolo valore e come accedo a quel valore". </gripe>
osman,

2
@osman Questo delicato tutorial su argparse potrebbe aiutare ...
lifebalance,

2
@ArtOfWarfare "argomenti opzionali" in questo contesto significa presumibilmente argomenti specificati con argomenti simili a opzioni come -fo --foo, mentre "numero esatto di argomenti da conoscere in anticipo" presumibilmente significa argomenti posizionali forniti senza alcun flag di opzione precedente.
mtraceur,

67

C'è anche il argparsemodulo stdlib (un "miglioramento" sul optparsemodulo di stdlib ). Esempio dall'introduzione ad 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))

Uso:

$ script.py 1 2 3 4
4

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

1
è solo una copia e incolla
blitu12345

3
@ blitu12345 al momento della pubblicazione della mia risposta non c'erano altre risposte che menzionassero argparse in alcun modo. Il modulo stesso non era in stdlib¶ Che cosa hai contro gli esempi di codice della documentazione? Perché pensi che sia necessario elaborare i tuoi esempi anziché quelli forniti dall'autore del modulo? E non mi piacciono le risposte solo link (non sono solo).
jfs,

1
Le persone che venivano qui avevano già un'idea di ciò che era nella documentazione e saranno qui solo per ulteriori chiarimenti sull'argomento. Lo stesso è stato il mio caso, ma quello che ho davvero trovato qui è una copia e incolla dai documenti originali. Pace!
blitu12345,

2
"Le persone che venivano qui avevano già un'idea di ciò che è nella documentazione" - dubito fortemente che questa ipotesi. in qualche modo.
sjas,

49

Un modo per farlo è usare sys.argv. Questo stamperà il nome dello script come primo argomento e tutti gli altri parametri che gli passerai.

import sys

for arg in sys.argv:
    print arg

49

Il docopt libreria è davvero liscia. Crea un argomento dettato dalla stringa di utilizzo per la tua app.

Ad esempio dal readme di 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)

4
Questo è rapidamente diventato il mio modo preferito di andare. Sta analizzando le stringhe, quindi è un po 'fragile, ma è fragile tutto in un unico posto e puoi vedere in anteprima la tua logica su try.docopt.org . Argomenti opzionali e reciprocamente esclusivi sono fatti in un modo davvero elegante.
gvoysey,

4
Sono disperato nel vedere il resto del codice per naval_fate.py
John Lawrence Aspden,

48

Se hai bisogno di qualcosa di veloce e non molto flessibile

main.py:

import sys

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

Quindi corri python main.py James Smith

per produrre il seguente output:

Ciao James Smith


Un uso più realistico sarebbe python main.py "James Smith"che mette James Smithin sys.argv[1]e produce una IndexErrorquando si tenta di utilizzare l'inesistente sys.argv[2]. Il comportamento delle citazioni dipenderà in qualche modo dalla piattaforma e dalla shell da cui si esegue Python.
Tripleee,

10
Non sono d'accordo sul fatto che il mio utilizzo sia meno realistico. Fai finta che il tuo programma debba conoscere il nome e il cognome esatti di una persona per eseguire lo script in un'azienda in cui le persone possono avere più nomi e cognomi? Se James Smith ha Joseph come nome o cognome in più, come farebbe a distinguere se Joseph è un nome o cognome in più se lo fai solo python main.py "James Joseph Smith"? Se sei interessato all'indice fuori dai limiti, puoi aggiungere un controllo per il numero di argomenti forniti. Meno realistico o meno, il mio esempio mostra come gestire più argomenti.
Kent Munthe Caspersen,

1
Tutte le altre risposte sono per la trama di una missione di atterraggio lunare. Sto semplicemente usando gmail-trash-msg.py MessageID. Questa risposta è diretta al MessageIDsuperamento del parametro di test sys.argv[1].
WinEunuuchs2Unix

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

19

Uso optparse da solo, ma mi piace molto la direzione che Simon Willison sta prendendo con la sua libreria optfunc recentemente introdotta . Funziona da:

msgstr "introspezione di una definizione di funzione (compresi i suoi argomenti e i loro valori predefiniti) e utilizzo di quello per costruire un parser di argomenti da riga di comando."

Quindi, ad esempio, questa definizione di funzione:

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

viene trasformato in questo testo di aiuto optparse:

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

8

Mi piace getopt da stdlib, ad esempio:

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

Ultimamente sto avvolgendo qualcosa di simile a questo per rendere le cose meno dettagliate (ad esempio, rendendo implicito "-h").


8

Di Pocoo click è più intuitivo, richiede meno scaldabagni ed è almeno potente quanto l'argparse.

L'unica debolezza che ho riscontrato finora è che non puoi fare molta personalizzazione per aiutare le pagine, ma di solito non è un requisito e docopt sembra la scelta chiara quando lo è.


7

Come puoi vedere optparse "Il modulo optparse è obsoleto e non verrà ulteriormente sviluppato; lo sviluppo continuerà con il modulo 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

Potresti essere interessato a un piccolo modulo Python che ho scritto per rendere ancora più semplice la gestione degli argomenti della riga di comando (open source e gratis da usare) - Commando


1
Esiste già un altro modulo di analisi della riga di comando chiamato Commando: github.com/lakshmivyas/commando . Si avvolge argparse usando decoratori.
Roberto Bonvallet,

1
reinvenzione di pitone e ruota
Derek,

4

Consiglio di consultare docopt come una semplice alternativa a questi altri.

docopt è un nuovo progetto che funziona analizzando il tuo messaggio di utilizzo --help anziché richiedere di implementare tutto da solo. Devi solo mettere il tuo messaggio di utilizzo nel formato POSIX.


4

Ancora un'altra opzione è argh . Si basa su argparse e ti consente di scrivere cose come:

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

Genererà automaticamente aiuto e così via, ed è possibile utilizzare i decoratori per fornire ulteriori indicazioni su come dovrebbe funzionare l'arg-parsing.


Questa è la soluzione migliore Usare arghè più facile di un altro lib o usare sys.
Juanjo Salvador,

Volevo piacere, arghma non è particolarmente adatto per scenari in cui il tuo massimo desiderio è non avere un comando con i sottocomandi.
Tripleee,

1
@tripleee YMMV, ma ho scoperto che questo era più un difetto nella documentazione che nella libreria stessa. Sembra perfettamente fattibile def frobnicate_spleches(...)definire una funzione che fa qualunque cosa faccia il tuo script, quindi lo fa if __name__ == '__main__': argh.dispatch_command(frobnicate_spleches)alla fine del file.
Rovina circolare

0

La mia soluzione è entrypoint2 . Esempio:

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

Testo guida:

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
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.