2009-01-31 24 views
27

Quindi sono in Linux e voglio che un programma accetti gli argomenti quando lo si esegue dalla riga di comando.Passare gli argomenti nel programma C dalla riga di comando

Per esempio,

./myprogram 42 -b -s

Allora il programma sarebbe memorizzare il numero 42 come un int ed eseguire alcune parti di codice a seconda di quali argomenti si arriva come -b o -s.

+0

Il formato canonico per una riga di comando passa argomenti di opzione come '-b' e '-s' prima di qualsiasi argomento non opzionale come '42'. Quindi, il formato standard e ortodosso della riga di comando sarebbe "./myprogram -b -s 42". Evitare di deviare da quello standard. [... altro nel prossimo commento ...] –

+0

Vedere la sezione 12 (Convenzioni di utilità) delle Definizioni di base dello standard POSIX su http://www.opengroup.org/onlinepubs/009695399/toc.htm. –

+1

@Jonathan Leffler: l'ordine non ha importanza. La funzione 'getopt_long' fa la cosa giusta indipendentemente dall'ordine. Vedi la mia risposta. – jfs

risposta

36

È possibile utilizzare getopt.

#include <ctype.h> 
#include <stdio.h> 
#include <stdlib.h> 
#include <unistd.h> 

int 
main (int argc, char **argv) 
{ 
    int bflag = 0; 
    int sflag = 0; 
    int index; 
    int c; 

    opterr = 0; 

    while ((c = getopt (argc, argv, "bs")) != -1) 
    switch (c) 
     { 
     case 'b': 
     bflag = 1; 
     break; 
     case 's': 
     sflag = 1; 
     break; 
     case '?': 
     if (isprint (optopt)) 
      fprintf (stderr, "Unknown option `-%c'.\n", optopt); 
     else 
      fprintf (stderr, 
        "Unknown option character `\\x%x'.\n", 
        optopt); 
     return 1; 
     default: 
     abort(); 
     } 

    printf ("bflag = %d, sflag = %d\n", bflag, sflag); 

    for (index = optind; index < argc; index++) 
    printf ("Non-option argument %s\n", argv[index]); 
    return 0; 
} 
+0

Ho aggiunto un esempio di codice. – jfs

+2

Non dovrebbe capire "gli argomenti principali che passano" prima? ;) – OscarRyz

+0

Funzionerà su Linux perché la funzione getopt() è GNU getopt() e normalmente non si imposta POSIXLY_CORRECT nell'ambiente, e GNU getopt() quindi elabora gli argomenti delle opzioni prima degli argomenti 'file', anche quando seguono un argomento di file come nell'esempio. Sulle piattaforme POSIX, non funzionerà ... –

25

In C, questo viene fatto usando argomenti passati alla funzione main():

int main(int argc, char *argv[]) 
{ 
    int i = 0; 
    for (i = 0; i < argc; i++) { 
     printf("argv[%d] = %s\n", i, argv[i]); 
    } 
    return 0; 
} 

Maggiori informazioni si possono trovare online come questo Arguments to main articolo.

+0

Mi dispiace, non è un x-ref terribilmente buono. C'è un bug nell'affermazione che "La dichiarazione dell'argomento argv è spesso il primo incontro di un programmatore inesperto con puntatori agli array di puntatori e può rivelarsi intimidatorio" (argv è un array di puntatori, non un puntatore a un array di puntatori). –

+1

Inoltre, la pagina successiva mostra un parser di opzioni ad hoc invece di usare i parser standard getopt() o getopt_long() - che è semplicemente un cattivo consiglio. No - non è un buon riferimento. –

+2

In C, un riferimento a un array è un indirizzo, proprio come un puntatore è un indirizzo. Quindi, argv può essere indicato come "un array" e "un puntatore a un array". Questa è una delle più belle simpatie di C e uno dei punti di confusione. –

6

Dai un'occhiata alla libreria getopt; è praticamente il gold standard per questo genere di cose.

10

considerare l'utilizzo di getopt_long(). Permette opzioni sia corte che lunghe in qualsiasi combinazione.

#include <stdio.h> 
#include <stdlib.h> 
#include <getopt.h> 

/* Flag set by `--verbose'. */ 
static int verbose_flag; 

int 
main (int argc, char *argv[]) 
{ 
    while (1) 
    { 
     static struct option long_options[] = 
    { 
     /* This option set a flag. */ 
     {"verbose", no_argument,  &verbose_flag, 1}, 
     /* These options don't set a flag. 
     We distinguish them by their indices. */ 
     {"blip", no_argument,  0, 'b'}, 
     {"slip", no_argument,  0, 's'}, 
     {0,   0,     0, 0} 
    }; 
     /* getopt_long stores the option index here. */ 
     int option_index = 0; 

     int c = getopt_long (argc, argv, "bs", 
       long_options, &option_index); 

     /* Detect the end of the options. */ 
     if (c == -1) 
    break; 

     switch (c) 
    { 
    case 0: 
     /* If this option set a flag, do nothing else now. */ 
     if (long_options[option_index].flag != 0) 
     break; 
     printf ("option %s", long_options[option_index].name); 
     if (optarg) 
     printf (" with arg %s", optarg); 
     printf ("\n"); 
     break; 
    case 'b': 
     puts ("option -b\n"); 
     break; 
    case 's': 
     puts ("option -s\n"); 
     break; 
    case '?': 
     /* getopt_long already printed an error message. */ 
     break; 

    default: 
     abort(); 
    } 
    } 

    if (verbose_flag) 
    puts ("verbose flag is set"); 

    /* Print any remaining command line arguments (not options). */ 
    if (optind < argc) 
    { 
     printf ("non-option ARGV-elements: "); 
     while (optind < argc) 
    printf ("%s ", argv[optind++]); 
     putchar ('\n'); 
    } 

    return 0; 
} 

correlati:

4

Invece di getopt(), si può anche considerare l'utilizzo di argp_parse() (un'interfaccia alternativa per la stessa libreria).

Da libc manual:

getopt è più standard (il breve opzione solo versione di esso è una parte dello standard POSIX), ma utilizzando argp_parse è spesso più facile, sia per molto semplice e molto complesso l'opzione strutture, perché fa più di il lavoro sporco per voi.

Ma sono sempre stato soddisfatto dello standard getopt.

N.B. GNU getopt con getopt_long è GNU LGPL.

+0

"getopt è GNU LGPL": dipende dal getopt. È stato implementato più volte. Quello in Mac OS X è concesso in licenza BSD. – dmckee

+0

E AT & T ha rilasciato uno nella metà degli anni '80 nel pubblico dominio, o qualcosa di molto vicino al dominio pubblico. D Il punto di McKee è molto valido - GNU getopt() [e getopt_long()] sono LGPL (o, le versioni precedenti sono GPL); non tutte le versioni di getopt() sono GPL o LGPL. –

+0

Sono d'accordo con i tuoi commenti e modifica il mio post. Grazie. – sastanin

4

Altri hanno colpito questo uno sulla testa:

  • gli argomenti standard per main(int argc, char **argv) vi darà l'accesso diretto alla linea di comando (dopo che è stato storpiato e token dalla shell)
  • ci sono molto impianto standard per analizzare la riga di comando: getopt() e getopt_long()

ma come avete visto il codice di usarli è un po 'prolisso, e piuttosto idomatic. Io generalmente spingerlo fuori di vista con qualcosa di simile:

typedef 
struct options_struct { 
    int some_flag; 
    int other_flage; 
    char *use_file; 
} opt_t; 
/* Parses the command line and fills the options structure, 
* returns non-zero on error */ 
int parse_options(opt_t *opts, int argc, char **argv); 

Allora come prima cosa principale:

int main(int argc, char **argv){ 
    opt_t opts; 
    if (parse_options(&opts,argc,argv)){ 
     ... 
    } 
    ... 
} 

o si potrebbe utilizzare una delle soluzioni proposte in Argument-parsing helpers for C/UNIX.

Problemi correlati