لا يقوم getopt بتحليل الوسائط الاختيارية إلى المعلمات
-
20-08-2019 - |
سؤال
في لغة C، لا يقوم getopt_long بتحليل الوسائط الاختيارية لمعلمات معلمات سطر الأوامر.
عندما أقوم بتشغيل البرنامج، لا يتم التعرف على الوسيطة الاختيارية كما هو موضح في المثال أدناه.
$ ./respond --praise John
Kudos to John
$ ./respond --blame John
You suck !
$ ./respond --blame
You suck !
هنا هو رمز الاختبار.
#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;
}
المحلول
وعلى الرغم من عدم ذكرها في وثائق سي العمومية أو صفحة رجل getopt، والحجج اختياري لمعلمات سطر الأوامر نمط طويل تتطلب "علامة يساوي '(=). مساحة تفصل بين سيطة اختيارية من المعلمة لا تعمل.
ومثال تشغيل مع رمز اختبار:
<اقتباس فقرة>$ ./respond --praise John
Kudos to John
$ ./respond --praise=John
Kudos to John
$ ./respond --blame John
You suck !
$ ./respond --blame=John
You suck , John!
اقتباس فقرة> نصائح أخرى
من المؤكد أن صفحة الدليل لا توثق ذلك بشكل جيد، ولكن الكود المصدري يساعد قليلاً.
باختصار:من المفترض أن تفعل شيئًا مثل ما يلي (على الرغم من أن هذا قد يكون مبالغًا فيه قليلاً):
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++];
}
/* ... */
من بين التعليقات السابقة _getopt_internal:
...
لو
getopt
يعثر على حرف خيار آخر، ويقوم بإرجاع هذا الحرف، تحديثoptind
وnextchar
حتى أن المكالمة التالية لgetopt
يمكن استئناف الفحص باستخدام حرف الخيار التالي أو عنصر ArgV.إذا لم يكن هناك المزيد من أحرف الخيارات،
getopt
عوائد -1.ثمoptind
هو الفهرس في ArgV من العناصر Argv الأولى التي ليست خيارًا.(تم توريث عناصر Argv بحيث تأتي تلك التي لا تكون خيارات الآن.)<-- a note from me: if the 3rd argument to getopt_long starts with a dash, argv will not be permuted
...
إذا تمت متابعة char في OptString بواسطة قولون ، فهذا يعني أنه يريد arg ، وبالتالي يتم إرجاع النص التالي في نفس عنصر argv ، أو نص argv العناصر التالية ،
optarg
.يعني اثنان من كولون خيار يريد arg اختياري ؛إذا كان هناك نص في عنصر ArgV الحالي ، يتم إرجاعهoptarg
, خلاف ذلكoptarg
تم ضبطه على الصفر....
...على الرغم من أنه عليك القيام ببعض القراءة بين السطور.ما يلي يفعل ما تريد:
#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;
}
وركضت أيضا في نفس المشكلة وجئت إلى هنا. ثم أدركت هذا. لم يكن لديك الكثير من حالة استخدام "optional_argument". إذا لا بد من وضع الخيار الذي تحقق من منطق البرنامج، إذا كان الخيار هو اختياري ثم لا تحتاج إلى القيام بأي شيء لأنه في مستوى getopt جميع الخيارات اختيارية، فهي ليست إلزامية، لذلك ليس هناك حالة استخدام "optional_argument". ويساعد هذا الأمل.
ملاحظة: للمثال المذكور أعلاه وأعتقد أن الخيارات الصحيحة --praise --praise اسم "اسم" --blame --blame اسم "اسم"
إذا كنت أكتب الحجة القادمة إلى المعلمة دون حرف مسافة لا يساوي يعمل أيضا. على سبيل المثال:
$ ./respond --blameJohn
You suck John!