باستخدام ' -- ' كعلامة نهاية الخيارات مع دفعة:: خيارات البرنامج
-
14-11-2019 - |
سؤال
الطريقة التقليدية للإشارة إلى نهاية الخيارات لبرامج سطر الأوامر هي مع الخيار --
.كيف يمكنني الحصول على دفعة:: خيارات البرنامج للتعرف على هذا كخيار وقبول بقية سطر الأوامر كوسائط موضعية?ما يلي لا يعمل:
namespace po = boost::program_options;
po::positional_options_description posOpts;
posOpts.add("keywords", 1);
posOpts.add("input", 1);
std::vector<std::string> final_args;
po::options_description desc("Allowed Options");
desc.add_options()
...
("", po::value< std::vector<std::string> >(&final_args)->multitoken(), "end of options")
...
;
po::command_line_parser(argc, argv).options(desc).positional(posOpts).run();
إذا أعطيت foo bar
كحجج ، لا أحصل على شيء في final_args
(كما هو متوقع) ، ولكن أيضا عندما أعطي -- foo bar
كحجج (عندما أتوقع أن أجد final_args[0] == "foo"
و final_args[1] == "bar"
).أفترض هنا أن --
هي حجة طويلة مع السلسلة الفارغة كاسم الوسيطة.إذا ، بدلا من ذلك ، فإنه من المفترض أن تفسر على أنها حجة قصيرة ، مع -
كاسم الحجة, كيف يمكنني تحديد ذلك?تغيير مواصفات الوسيطة من ""
إلى ",-"
لا يؤثر على النتيجة ، بقدر ما أستطيع أن أرى.
كيف يمكن للمرء الحصول على دفعة:: خيارات البرنامج للتعامل معها --
صحيح?
تحرير: إليك محاولة للقيام بما اقترحه تيم سيلفستر من خلال إنشاء extra_style_parser
:
std::vector<po::option> end_of_opts_parser(std::vector<std::string>& args) {
std::vector<po::option> result;
std::vector<std::string>::const_iterator i(args.begin());
if (i != args.end() && *i == "--") {
for (++i; i != args.end(); ++i) {
po::option opt;
opt.string_key = "pargs";
opt.original_tokens.push_back(*i);
result.push_back(opt);
}
args.clear();
}
return result;
}
"pargs"
تمت إضافته إلى خيارات مثل هذا:
("pargs", po::value< std::vector<std::string> >(&pargs), "positional arguments")
تشغيل هذا مع --
في قائمة الوسيطة يسبب أ required_option
استثناء.(أحصل على نتائج مماثلة إذا بدلا من جعل po::option
لكل الأرجنتين زائدة ، وأنا حزمة كل منهم في po::option::original_tokens
في واحد po::option
.)
المحلول
كان لدي نفس السؤال ، لكنني تخلت عنه.
أعتقد أن طريقة القيام بذلك هي الاتصال program_options::command_line_parser::extra_style_parser()
, ، تمريرها دالة تأخذ متجها من السلسلة بالرجوع وإرجاع متجه option
س (انظر ال style_parser
اكتبصحف في كمدلاين.هب).
ستحتاج وظيفتك إلى اكتشاف أن الرمز المميز الأول هو " -- " ، وإنشاء رمز جديد option
الكائن ، ضع كل ما تبقى من الرموز المميزة في الإدخال في option
متجه القيمة وإفراغ متجه الإدخال.انظر program_options::detail::cmdline::parse_long_option
, ، إلخ.، في libs/program_options/src/cmdline.cpp
عن شيء لتبدأ.
ستحتاج على الأرجح إلى تسجيل قيمة خيار محددة لاستخدامها بحيث يمكنك بسهولة العثور على هذا الخيار الخاص option
الكائن في نهاية التحليل واستخراج مجموعة من المعلمات غير الخيار إضافية منه.
أتمنى أن أعطيك بعض التعليمات البرمجية ولكن لم أحصل على القيام بذلك في الواقع ، انتهى بي الأمر مجرد أخذ المعلمات الإضافية واحد في كل سطر على ستدين.
تحرير:
شعرت بالسوء حيال توجيهك في اتجاه لم يحل المشكلة ، لذلك عدت وعملت.المشكلة هي أن إدخال الوسيطة الموضعية لم يتم إعداده لقبول رموز متعددة ولم تكن تملأ value
.ال program_options
يتوقع الكود كليهما أو لا يعمل.
وهنا رمز الكامل الذي يعمل بالنسبة لي:
#include <boost/program_options.hpp>
#include <iostream>
namespace po = boost::program_options;
typedef std::vector<std::string> stringvec;
std::vector<po::option> end_of_opts_parser(stringvec& args) {
std::vector<po::option> result;
stringvec::const_iterator i(args.begin());
if (i != args.end() && *i == "--") {
for (++i; i != args.end(); ++i) {
po::option opt;
opt.string_key = "pargs";
opt.value.push_back(*i); // <== here
opt.original_tokens.push_back(*i);
result.push_back(opt);
}
args.clear();
}
return result;
}
int main(int argc, char* argv[])
{
po::options_description desc("Allowed Options");
desc.add_options()
("help,h", "produce help message")
("pargs", po::value<stringvec>()->multitoken(), "positional arguments");
// and here ^^^^^^^^^^^^^
po::command_line_parser clparser(argc, argv);
clparser.extra_style_parser(end_of_opts_parser);
po::variables_map vm;
po::store(clparser.options(desc).run(), vm);
po::notify(vm);
bool const help = !vm["help"].empty();
std::cout << "help = " << help << " - ";
// in addition, you don't need to use a separate vector of strings:
stringvec const& pargs = vm["pargs"].as<stringvec>();
std::copy(pargs.begin(), pargs.end(),
std::ostream_iterator<std::string>(std::cout, ","));
return 0;
}
عند تشغيل مع -h -- foo bar baz
يطبع help = 1 - foo,bar,baz,
.
نصائح أخرى
أنا مرتبك قليلا لأن boost::program_options
بالفعل يفعل هذا من تلقاء نفسه:
$ ./testprog --the-only-option=23 aa --unknown bb
terminate called after throwing an instance of 'boost::exception_detail::clone_impl<boost::exception_detail::error_info_injector<boost::program_options::unknown_option> >'
what(): unknown option unknown
Aborted
$ ./testprog --the-only-option=23 -- aa --unknown bb
the only option: 23
positional: aa
positional: --unknown
positional: bb
البرنامج:
#include <boost/program_options.hpp>
#include <iostream>
#include <vector>
using namespace std;
namespace po = boost::program_options;
static bool handle_command_line(int argc, char *argv[])
{
po::options_description desc("Allowed options");
desc.add_options()
("help", "Describe command line options")
("the-only-option", po::value<string>(), "some option")
;
po::options_description hidden;
hidden.add_options()
("positional", po::value<vector<string> >())
;
po::options_description all_options;
all_options.add(desc).add(hidden);
po::positional_options_description p;
p.add("positional", -1);
po::variables_map vm;
po::store(po::command_line_parser(argc, argv).
options(all_options).positional(p).run(), vm);
po::notify(vm);
if (vm.count("help")) {
cout << "Usage: " << argv[0] << " [options] [args]" << endl;
cout << desc << "\n";
return false;
}
if (vm.count("the-only-option"))
cout << "the only option: " << vm["the-only-option"].as<string>() << endl;
if (vm.count("positional")) {
const vector<string> &v = vm["positional"].as<vector<string> >();
vector<string>::const_iterator it = v.begin();
for (; it != v.end(); ++it)
cout << "positional: " << *it << endl;
}
return true;
}
int main(int argc, char *argv[])
{
if (!handle_command_line(argc, argv))
return 1;
return 0;
}
هناك بسيطة ، غير مرضية الحل:قبل تسليم argv
إلى command_line_parser
, تحقق ما إذا كان --
يحدث في ذلك.أنا إعادة تعيين argc
موقف --
لإخفائه و الحجج زائدة من command_line_parser
.ثم عند الانتهاء من تحليل ، والتعامل مع الموضعية الحجج بعد --
باليد.Blech!