2009-02-11 9 views
5

¿Alguien me puede ayudar con la función getopt?biblioteca de procesamiento de línea de comandos - getopt

Cuando hago lo siguiente en el principal:

char *argv1[] = {"testexec","-?"}; 
char *argv2[] = {"testexec","-m","arg1"}; 
int cOption; 
/* test for -? */ 

setvbuf(stdout,(char*)NULL,_IONBF,0); 
printf("\n argv1 "); 
while ((cOption = getopt (2, argv1, "m:t:n:fs?")) != -1) { 
    switch(cOption){ 
     case 'm': 
      printf("\n -m Arg : %s \n",optarg); 
      break; 
     case '?': 
      printf("\n -? Arg "); 
      break; 
     case 'n': 
      printf("\n -n Arg : %s \n",optarg); 
      break; 
    } 
} 

printf("\n argv2 "); 

while ((cOption = getopt (3, argv2, "m:t:n:fs?")) != -1) { 
    switch(cOption){ 
     case 'm': 
      printf("\n -m Arg : %s \n",optarg); 
      break; 
     case '?': 
      printf("\n -? Arg : %s \n",optarg); 
      break; 
     case 'n': 
      printf("\n -n Arg : %s \n",optarg); 
      break; 
    } 
} 
 

estoy corriendo este código en RHEL3 que utiliza vieja versión de libc. No sé cuál ser exacto.

Ahora el problema es que getopt no funciona la segunda vez con argv2. Pero si comento la primera llamada de getopt con argv1, funciona.

¿Puede alguien decirme qué estoy haciendo mal aquí?

Respuesta

12

argv1 y 2 deben terminar en 0:

char* argv1[] = {"par1", "par2", 0}; 

Edición: OK, he leído la página del manual getopt y encontré esto:

El optind variable es el índice de la siguiente elemento para ser procesado en argv. El sistema inicializa este valor en 1. La persona que llama puede restablecerlo a 1 para reiniciar el escaneo de la misma argv, o al escanear un nuevo vector de argumento.

Por lo tanto, hacer optind = 1 entre las dos llamadas en getopt hace que funcione como se esperaba.

+0

Buena respuesta, pero si bien es cierto, intenté cambiarla en el código de ejemplo y no solucionó el problema específico que se le preguntaba. –

+0

David, tienes razón. Acabo de detectar ese error y olvidé el resto :) Edité la respuesta, ya que noté que si actualiza el valor optind a 1, el código funciona como se esperaba. Recuerdos –

+2

Cuidado: el estándar POSIX no establece que reiniciar la opción a 1 reiniciará getopt() al estado inicial, especialmente si no analizó por completo los primeros argumentos. Por ejemplo, si el primer argumento es -xy y se detiene después de procesar x, no hay garantía de que funcione un reinicio de optind. –

4

La función getopt() utiliza algunas variables globales, como optind y optarg, para almacenar información de estado entre llamadas. Después de que termine de procesar un conjunto de opciones, quedan datos en esas variables que causan problemas con el siguiente conjunto de opciones. Podría intentar restablecer el estado de getopt entre llamadas borrando las variables, pero no estoy seguro de que funcione, ya que la función podría usar otras variables que no están documentadas y nunca sabría si las había obtenido. todas; además, sería absolutamente no portable (es decir, si la implementación de getopt() cambia, su código se rompe). Vea el man page para más detalles. Es mejor no usar getopt() para más de un conjunto de argumentos en un programa dado si puede evitarlo.

No estoy seguro de si hay una función real para restablecer el estado getopt (o quizás una versión reentrante de la función, que le permite almacenar el estado en sus propias variables) ... Me parece recordar haber visto algo así una vez, pero no puedo encontrarlo ahora que lo miro: -/

1

¿Hay alguna razón por la que no estés usando getopt_long()? En la mayoría de las plataformas, getopt() solo llama a _getopt_long() con un interruptor para deshabilitar los argumentos largos. Ese es el caso de casi todas las plataformas que conozco (aún en uso), incluyendo Linux, BSD e incluso sistemas operativos emergentes como HelenOS, sé que fui el que transfirió getopt a su libc :)

Es mucho más fácil para CUALQUIERA que use su programa para tener opciones largas al menos hasta que se acostumbren a usarlo.

getopt_long() le permitirá usar dos (o más) índices opcionales que pueden permanecer 'activos' después de que terminen de procesar los argumentos, solo el interno (global, no reentrante) tendría que ser reestablecido que no es gran cosa.

Esto le permite comparar fácilmente el recuento de argumentos con el número de opciones realmente aprobadas en ambas invocaciones con muchos otros beneficios.por favor considere no usar la interfaz anticuada.

Mira getopt.h, verás a qué me refiero.

+2

¿Definir la mayoría de las plataformas? HP-UX, Solaris, AIX - getopt() no llama a getopt_long(). Eso es 3 de 6 variantes de Unix (BSD, Linux, MacOS X son las otras que importan). –

2

Como se indica en la página del manual:

"Un programa que escanea múltiples vectores de argumentos, o vuelve a explorar el mismo vector más de una vez, y quiere hacer uso de extensiones de GNU, como '+' y '-' al comienzo de Optstring, o cambia el valor de POSIXLY_CORRECT entre escaneos, debe reinicializar getopt() reiniciando optind a 0, en lugar del valor tradicional de 1. (Restablecer a 0 fuerza la invocación de una rutina de inicialización interna que vuelve a verificar POSIXLY_CORRECT y comprueba las extensiones de GNU en optstring.) "

Cuestiones relacionadas