Question

En C, getopt_long n'analyse pas les arguments facultatifs des paramètres de paramètres de ligne de commande.

Lorsque j'exécute le programme, l'argument facultatif n'est pas reconnu, comme dans l'exemple ci-dessous.

$ ./respond --praise John
Kudos to John
$ ./respond --blame John
You suck !
$ ./respond --blame
You suck !

Voici le code de test.

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

int main(int argc, char ** argv )
{
    int getopt_ret, option_index;
    static struct option long_options[] = {
               {"praise",  required_argument, 0, 'p'},
               {"blame",  optional_argument, 0, 'b'},
               {0, 0, 0, 0}       };
    while (1) {
        getopt_ret = getopt_long( argc, argv, "p:b::",
                                  long_options,  &option_index);
        if (getopt_ret == -1) break;

        switch(getopt_ret)
        {
            case 0: break;
            case 'p':
                printf("Kudos to %s\n", optarg); break;
            case 'b':
                printf("You suck ");
                if (optarg)
                    printf (", %s!\n", optarg);
                else
                    printf ("!\n", optarg);
                break;
            case '?':
                printf("Unknown option\n"); break;
        }
    } 
    return 0;
}
Était-ce utile?

La solution

Bien que cela ne soit pas mentionné dans la documentation de la glibc ni dans la page de manuel de getopt, les arguments facultatifs des paramètres de ligne de commande de style long nécessitent le "signe égal" (=). L'espace séparant l'argument optionnel du paramètre ne fonctionne pas.

Un exemple exécuté avec le code de test:

$ ./respond --praise John
Kudos to John
$ ./respond --praise=John
Kudos to John
$ ./respond --blame John
You suck !
$ ./respond --blame=John
You suck , John!

Autres conseils

La page de manuel ne la documente certes pas très bien, mais le code source aide un peu.

Brièvement: vous êtes censé faire quelque chose comme ce qui suit (bien que cela puisse être un peu trop pédant):

if(   !optarg
   && optind < argc // make sure optind is valid
   && NULL != argv[optind] // make sure it's not a null string
   && '\0' != argv[optind][0] // ... or an empty string
   && '-' != argv[optind][0] // ... or another option
  ) {
  // update optind so the next getopt_long invocation skips argv[optind]
  my_optarg = argv[optind++];
}
/* ... */
  

Parmi les commentaires précédant _getopt_internal:

     

...

     

Si getopt trouve un autre caractère d'option, il renvoie ce caractère,    mettre à jour optind et nextchar afin que le prochain appel à <-- a note from me: if the 3rd argument to getopt_long starts with a dash, argv will not be permuted puisse   reprenez l’analyse avec le caractère d’option ou l’élément ARGV suivant.

     

S'il n'y a plus de caractères d'option, optarg renvoie -1.   Alors <=> est l'index en ARGV du premier élément ARGV   Ce n'est pas une option. (Les éléments ARGV ont été permutés   de sorte que ceux qui ne sont pas des options viennent maintenant en dernier.) <=>

     

...

     

Si un caractère dans OPTSTRING est suivi de deux points, cela signifie qu'il veut un argument,   de sorte que le texte suivant dans le même élément ARGV, ou le texte de l'élément suivant   L'élément ARGV est renvoyé dans <=>. Deux colons signifient une option qui   veut un argument optionnel; s'il y a du texte dans l'élément ARGV actuel,   il est renvoyé dans <=>, sinon <=> est défini sur zéro .

     

...

... bien que vous deviez lire un peu entre les lignes. Ce qui suit fait ce que vous voulez:

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

int main(int argc, char* argv[] ) {
  int getopt_ret;
  int option_index;
  static struct option long_options[] = {
      {"praise",  required_argument, 0, 'p'}
    , {"blame",  optional_argument, 0, 'b'}
    , {0, 0, 0, 0}
  };

  while( -1 != ( getopt_ret = getopt_long(  argc
                                          , argv
                                          , "p:b::"
                                          , long_options
                                          , &option_index) ) ) {
    const char *tmp_optarg = optarg;
    switch( getopt_ret ) {
      case 0: break;
      case 1:
        // handle non-option arguments here if you put a `-`
        // at the beginning of getopt_long's 3rd argument
        break;
      case 'p':
        printf("Kudos to %s\n", optarg); break;
      case 'b':
        if(   !optarg
           && NULL != argv[optindex]
           && '-' != argv[optindex][0] ) {
          // This is what makes it work; if `optarg` isn't set
          // and argv[optindex] doesn't look like another option,
          // then assume it's our parameter and overtly modify optindex
          // to compensate.
          //
          // I'm not terribly fond of how this is done in the getopt
          // API, but if you look at the man page it documents the
          // existence of `optarg`, `optindex`, etc, and they're
          // not marked const -- implying they expect and intend you
          // to modify them if needed.
          tmp_optarg = argv[optindex++];
        }
        printf( "You suck" );
        if (tmp_optarg) {
          printf (", %s!\n", tmp_optarg);
        } else {
          printf ("!\n");
        }
        break;
      case '?':
        printf("Unknown option\n");
        break;
      default:
        printf( "Unknown: getopt_ret == %d\n", getopt_ret );
        break;
    }
  }
  return 0;
}

J'ai aussi rencontré le même problème et je suis venu ici. Puis j'ai réalisé ceci. Vous n'avez pas beaucoup de cas d'utilisation de & Quot; optional_argument & Quot; . Si une option est requise, vous vérifiez à partir de la logique du programme. Si une option est facultative, vous ne devez rien faire car, au niveau de getopt, toutes les options sont facultatives, elles ne sont pas obligatoires et aucun cas d'utilisation de & Quot; optional_argument < !> quot. J'espère que cela vous aidera.

ps: pour l'exemple ci-dessus, je pense que les bonnes options sont --praise --praise-name " nom " --blame --blame-name " nom "

Si vous écrivez l'argument à côté du paramètre sans espace, ni l'un ni l'autre ne fonctionnent également. Par exemple:

$ ./respond --blameJohn
You suck John!
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top