ubuntuusers.de

C: Problem mit getopt()

Status: Gelöst | Ubuntu-Version: Ubuntu 14.04 (Trusty Tahr)
Antworten |

Dakuan

Avatar von Dakuan

Anmeldungsdatum:
2. November 2004

Beiträge: 6479

Wohnort: Hamburg

Eigentlich hatte ich die Funktion getopt() schon längere Zeit ohne Probleme genutzt. Aber jetzt gibt es plötzlich Probleme. Hier mal das entsprechende Code Fragment:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
...
	while ((c = getopt( argc, argv, "iasv:hn" )) != -1) {
		switch (c) {
		    case 'i':   printf( "%s\n", version );
		                exit( 0 );
		    case 'a':   filter_flag = 0;                break;
		    case 's':   want_stat = 0;                  break;
		    case 'v':   verbose = atoi( optarg );       break;
		    case 'n':   no_action = 1;                  break;
		    case 'h':   printf( "  %s %s\n", argv[0], version );
		                help();                         break;
		    case '?':   fprintf( stderr, "Unrecognized option \n");
			            break;
                    default:    fprintf( stderr, "invalid option\n\n" );
                                help();
                                exit( -3 );
		}
	}
...

Die zugehörige Eingabezeile ist:

$ ./edcom -a -v -n img_filter2.txt test

Hinter dem Parameter "v" sollte eigentlich eine Zahl stehen. Durch dessen Fehlen (Userfehler) tritt das Problem auf. Der nachfolgende Parameter "-n" (für no action) wird dann nicht mehr bearbeitet, was in diesem Fall zu fehlerhaftem Verhalten führt.

Ich verstehe aber nicht, warum dann die Datei "img_filter2.txt" und die nachfolgende Verzeichnisangabe "test" trotzdem abgearbeitet werden (aber leider mit falschen Einstellungen).

Es funktioniert nur, wenn die geforderte Zahl ohne Abstand eingegeben wird.

Daher meine Frage: Wie könnte ich erkennen, das die Eingabe fehlerhaft ist? Oder ist diese Funktion generell nicht empfehlenswert.

p.s: Die "default" Zeile hatte ich erst nach studieren des Beispiels in den man pages hinzugefügt, was aber nichts geändert hat.

atze

Anmeldungsdatum:
11. März 2010

Beiträge: 83

Wenn bei einer Option ein Argument fehlt, dann gibt getopt() ":" zurück.
Du brauchst dafür also ein weiteres case, z.B.:

case ':':
    printf("-%c ohne Argument\n", optopt);
    break;

Dakuan

(Themenstarter)
Avatar von Dakuan

Anmeldungsdatum:
2. November 2004

Beiträge: 6479

Wohnort: Hamburg

Danke für den Hinweis. Ich habe mir daraufhin die Doku nochmal gezielt angesehen und es sowohl mit '?' als auch mit ':' ausprobiert. Beides funktioniert nicht zuverlässig, wenn nach der entsprechenden Option noch weiterer Text in der Kommandozeile steht.

Ich muss da wohl bei der Auswertung zumindest noch eine Plausibilitätsprüfung einbauen, da getopt() das nicht macht (oder auch nicht kann). Da habe ich wohl jahrelang zu viel erwartet.

Nur komisch, dass das immer gut gegangen ist, wo ich doch fast Tippfehler Weltmeister bin.

rklm Team-Icon

Projektleitung

Anmeldungsdatum:
16. Oktober 2011

Beiträge: 13166

Dakuan schrieb:

Danke für den Hinweis. Ich habe mir daraufhin die Doku nochmal gezielt angesehen und es sowohl mit '?' als auch mit ':' ausprobiert. Beides funktioniert nicht zuverlässig, wenn nach der entsprechenden Option noch weiterer Text in der Kommandozeile steht.

Hängt das vielleicht davon ab, ob die Option noch ein Argument hat oder nicht? Hast Du das mal systematisch ausprobiert?

Ich muss da wohl bei der Auswertung zumindest noch eine Plausibilitätsprüfung einbauen, da getopt() das nicht macht (oder auch nicht kann). Da habe ich wohl jahrelang zu viel erwartet.

Das kann ich mir nicht vorstellen, dass Du da selbst noch etwas herum bauen musst. Ich würde eher auf einen Nutzungsfehler tippen. Lieber noch einmal in Ruhe die Doku studieren. Meist sind Programme sehr deterministisch. 😉

Dakuan

(Themenstarter)
Avatar von Dakuan

Anmeldungsdatum:
2. November 2004

Beiträge: 6479

Wohnort: Hamburg

Hängt das vielleicht davon ab, ob die Option noch ein Argument hat oder nicht? Hast Du das mal systematisch ausprobiert?

Ja, ich habe das mal ausprobiert und mit de Debugger geprüft was da zurück kommt. Immer wenn ein Argument folgen soll, wird der nächste String aus argv[] übergeben. Ein Fehler kommt nur, wenn da nichts mehr drinn ist.

Und ich komme auch langsam zu der Überzeugung, das es gar nicht anders geht. Woher soll getopt wissen, ob da z.B. Text oder eine Zahl folgen soll? Die einzige Lösung die mir dazu einfällt, währe, wenn getopt es nicht erlauben würde, dass zwischen den Optionen und ihren Argumenten Leerzeichen sein dürfen.

Als Abhilfe prüfe ich jetzt, ob da eine Zahl folgt.

rklm Team-Icon

Projektleitung

Anmeldungsdatum:
16. Oktober 2011

Beiträge: 13166

Dakuan schrieb:

Hängt das vielleicht davon ab, ob die Option noch ein Argument hat oder nicht? Hast Du das mal systematisch ausprobiert?

Ja, ich habe das mal ausprobiert und mit de Debugger geprüft was da zurück kommt. Immer wenn ein Argument folgen soll, wird der nächste String aus argv[] übergeben. Ein Fehler kommt nur, wenn da nichts mehr drinn ist.

Ja, das ist das normale Verhalten.

Und ich komme auch langsam zu der Überzeugung, das es gar nicht anders geht. Woher soll getopt wissen, ob da z.B. Text oder eine Zahl folgen soll?

Prinzipiell wäre es natürlich denkbar, einen Kommandozeilenparser zu bauen, der das berücksichtigt ("OptionParser" in Ruby kann das z.B.). Aber getopt() kann das natürlich nicht, weil man ihm die Information ja gar nicht geben kann (der Optionsstring erlaubt ja nur die Angabe "mit oder ohne Parameter").

Die einzige Lösung die mir dazu einfällt, währe, wenn getopt es nicht erlauben würde, dass zwischen den Optionen und ihren Argumenten Leerzeichen sein dürfen.

Das würde aber wieder unübersichtlich, wenn der nächste Buchstabe auch eine gültige Option wäre, denn prinzipiell ist es ja erlaubt mehrere Optionswerte mit einem Strich anzugeben.

Als Abhilfe prüfe ich jetzt, ob da eine Zahl folgt.

Ja, mit getopt() musst Du die Werte selbst validieren. Das finde ich aber gar nicht so schlimm, weil man das oft sowieso machen muss (z.B. weil eine Zahl nur in einem bestimmten Bereich liegen darf usw.).

Es gibt ja auch noch getopt_long() für leicht ausgefeiltere Optionsverarbeitung.

Dakuan

(Themenstarter)
Avatar von Dakuan

Anmeldungsdatum:
2. November 2004

Beiträge: 6479

Wohnort: Hamburg

Ja, mit getopt() musst Du die Werte selbst validieren. Das finde ich aber gar nicht so schlimm, weil man das oft sowieso machen muss (z.B. weil eine Zahl nur in einem bestimmten Bereich liegen darf usw.).

Da hatte ich mir das bisher immer einfach gemacht, da z.B. bei bei Beginn eines Projektes die Abstufungen der "Verbosität" noch unbekannt war. Ich frage dann immer ab größer als ein bestimmter Schwellbert ist. Da geht dann auch 32767.

Das würde aber wieder unübersichtlich, wenn der nächste Buchstabe auch eine gültige Option wäre, denn prinzipiell ist es ja erlaubt mehrere Optionswerte mit einem Strich anzugeben.

Ich denke genau das ist eines der Probleme. Als ich noch unter Windows CLI Programme geschrieben hatte, hatte ich genau das dem Benutzer als Fehler vor die Füße geworfen.

Es gibt ja auch noch getopt_long() für leicht ausgefeiltere Optionsverarbeitung.

In meinem speziellen Fall währe da wohl getopt_long_only() besser.

Aber langfristig gesehen, werde ich wohl alle Tools, die nicht auch für Scripte vorgesehen sind, auf GUI umstellen. Da gibt es zwar auch genug Probleme, aber wenn ich da ein Häkchen bei "Testlauf" mache, sehe ich, das es beim Programm angekommen ist.

Antworten |