Я пытаюсь проанализировать аргументы командной строки, используя getopt()
в c++
:
#include <unistd.h>
#include <iostream>
int main(int argc, char** argv) {
int opt;
opterr = 0; // Don't allow getopt to print err messages
// Parse command line args using getopt
// "s:" means s is a required argument
while (optind < argc) {
if ((opt = getopt(argc, argv, "as:")) != -1) {
// std::cout << char(opt) << "\n";
switch (opt) {
case 'a':
std::cout << "flag 'a' set" << "\n";
break;
case 's':
std::cout << "got argument for option 's': " << optarg << "\n";
break;
case '?': // Unknown option
if (optopt == 's')
std::cerr << "'s' option requires an argument -- "
<< char(optopt) << "\n";
std::cerr << "Invalid option -- "
<< char(optopt) << "\n";
break;
default:
break;
}
}
else {
std::cout << "Non option argument: " << argv[optind] << "\n";
optind++;
}
}
}
Это работает, как и ожидалось, на моем Ma c. Я скомпилировал, используя g++ -g -std=c++11
. Это вывод для g++ -v
:
Configured with: --prefix=/Applications/Xcode.app/Contents/Developer/usr --with-gxx-include-dir=/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/c++/4.2.1
Apple clang version 11.0.0 (clang-1100.0.33.17)
Target: x86_64-apple-darwin19.3.0
Thread model: posix
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin
Это вывод во время выполнения:
$ ./a.out -a -s 12 file_path1 file_path2 -s 123
flag 'a' set
got argument for option 's': 12
Non option argument: file_path1
Non option argument: file_path2
got argument for option 's': 123
Но, когда я запускаю это на машине linux (после компиляции с те же флаги), я получаю другой вывод:
$ ./a.out -a -s 12 file_path1 file_path2 -s 123
flag 'a' set
got argument for option 's': 12
got argument for option 's': 123
Вот вывод для g++ -v
на linux:
Using built-in specs.
COLLECT_GCC=g++
COLLECT_LTO_WRAPPER=/usr/libexec/gcc/x86_64-redhat-linux/4.8.5/lto-wrapper
Target: x86_64-redhat-linux
Configured with: ../configure --prefix=/usr --mandir=/usr/share/man --infodir=/usr/share/info --with-bugurl=http://bugzilla.redhat.com/bugzilla --enable-bootstrap --enable-shared --enable-threads=posix --enable-checking=release --with-system-zlib --enable-__cxa_atexit --disable-libunwind-exceptions --enable-gnu-unique-object --enable-linker-build-id --with-linker-hash-style=gnu --enable-languages=c,c++,objc,obj-c++,java,fortran,ada,go,lto --enable-plugin --enable-initfini-array --disable-libgcj --with-isl=/builddir/build/BUILD/gcc-4.8.5-20150702/obj-x86_64-redhat-linux/isl-install --with-cloog=/builddir/build/BUILD/gcc-4.8.5-20150702/obj-x86_64-redhat-linux/cloog-install --enable-gnu-indirect-function --with-tune=generic --with-arch_32=x86-64 --build=x86_64-redhat-linux
Thread model: posix
gcc version 4.8.5 20150623 (Red Hat 4.8.5-39) (GCC)
Я также тестировал с g++ v9.2
на Linux, но вывод остается прежним. Я даже установил g++ v9.3
на macOS, используя brew
, и я все еще получаю те же результаты.
Копая эту проблему немного дальше, я обнаружил, что linux использует расширенную версию (это может быть документацией для linux версии ) getopt
. Эта версия в основном анализирует все аргументы от 1
до argc
независимо от того, встречает ли он неопциональный аргумент или нет. Он обновляет optind
до следующего параметра параметра idx (переходит, если между ними есть неопциональные аргументы). Принимая во внимание, что в macOS он останавливается на первом аргументе без опций (см. this manpage ). Он не будет автоматически увеличивать optind
до следующего параметра idx аргумента.
Одним из возможных решений является обнаружение аргументов, не являющихся параметрами, отдельно от while()
l oop , Но я пытаюсь выяснить, отсутствует ли какой-либо флаг, или есть какой-то другой обходной путь, который позволил бы компилятору использовать расширенную версию getopt
в macOS.
Спасибо!