2015-01-18 2 views
0

Мне интересно, как лучше обработать несколько аргументов командной строки. Я видел аргументы командной строки, сделанные с операторами switch и case, такими как:Несколько аргументов командной строки в C

while ((x = getopt(argc, argv, "bic:")) != -1){ 
switch (x){ 
    case 'b': 
    //do something 
    break; 
    case 'i': 
    //do something 
    break; 
    case 'c': 
    //do something 
    break; 
    default: 
    break; 
} 

Это прекрасно работает. Тем не менее, он не очень хорошо работает с несколькими аргументами командной строки. Для проекта, над которым я работаю, если я введу несколько аргументов, я хотел бы, чтобы это было комбинацией двух случаев, если это имеет смысл. Поэтому разделение между случаями немного раздражает ... Наверное, я мог бы делать отдельные случаи для каждой комбинации, например case: 'ib' или case: 'ibc' Но есть ли более простое решение?

Кроме того, я пытаюсь найти решение, в котором не имеет значения порядок ввода аргументов. a.out -b -c должен быть таким же, как a.out -c -b

+0

Ну, у вас уже есть цикл, поэтому ваш код уже обрабатывает несколько аргументов ('break' просто выходит из' switch', а не цикла). В чем именно проблема? – NPE

+0

Вы можете установить переменные 'got_flag_b',' got_flag_c' и т. Д. В ваш 'switch' и только после того, как вы зациклились на всех параметрах, запустите свою прикладную логику в зависимости от значений этих переменных.Существует [расширение GNU] (https://www.gnu.org/software/libc/manual/html_node/Getopt.html), чтобы обрабатывать длинные варианты, но я думаю, что это примерно так, как вы можете идти на C без используя генерацию кода. – 5gon12eder

+0

Не то, что я использую getopt, но этот код обрабатывает несколько аргументов (отсюда и цикл). Для части «порядок не имеет значения» вы должны просто установить булевские флаги в этом цикле, а затем просто действовать в соответствии с флагами. –

ответ

0

Для чего я понимаю из ваших комментариев, я ожидал бы, что код будет выглядеть примерно так. Непонятно, почему у вас есть аргумент c.

int main(int argc, char **argv) 
{ 
    int opt; 
    int i_flag = 0; 
    int b_flag = 0; 
    int c_flag = 0; 

    while ((opt = getopt(argc, argv, "bci")) != -1) 
    { 
     switch (opt) 
     { 
     case 'b': 
      b_flag = 1; 
      break; 
     case 'c': 
      c_flag = 1; 
      break; 
     case 'i': 
      i_flag = 1; 
      break; 
     default: 
      fprintf(stderr, "Usage: %s [-bci] [file ...]\n", argv[0]); 
      exit(EXIT_FAILURE); 
     } 
    } 

    if (optind < argc) 
    { 
     for (int i = optarg; i < argc; i++) 
     { 
      FILE *fp = fopen(argv[i], "r"); 
      if (fp == 0) 
       fprintf(stderr, "%s: failed to open file %s\n", argv[i]); 
      else 
      { 
       process_file(fp, argv[i], b_flag, c_flag, i_flag); 
       fclose(fp); 
      } 
     } 
    } 
    else 
    { 
     process_file(stdin, "-", b_flag, c_flag, i_flag); 
    } 
    return 0; 
} 

Предупреждение: Неоткомпилированный код.

process_file() функция имеет сигнатуру, такие как:

void process_file(FILE *fp, const char *fn, int b_flag, int c_flag, int i_flag); 

Если вы хотите переписать файлы, вы должны решить, будете ли вы обрабатывать стандартный ввод (без имени файла), и если да, то как. Если вы просто напишете новый файл на стандартный вывод, легко обрабатывать и стандартный ввод.

Вы можете изменить код, чтобы определить, удалось ли выполнить process_file() (например, оно возвращает целое число вместо void) и изменить статус выхода программы в соответствии с тем, успешно ли были обработаны все файлы. Вы можете решить, что вашим функциям не требуется имя файла (что позволяет вам указывать имя, например "-" или "/dev/stdin" для стандартного ввода).

Вы можете сделать флаги глобальными переменными, а функция process_file() может применять соответствующие преобразования к каждой строке. Вы можете сделать несколько преобразований для каждого файла, открыв и закрыв файл между каждым преобразованием или перематывая файл между каждым преобразованием, если хотите. Однако это будет медленнее, чем выполнение трех преобразований параллельно.

ГНУ версия getopt() обеспечивает аргумент перестановку, так что вы можете выполнить:

program -b -c -i name-of-file 
program name-of-file -b -c -i 
program -b name-of-file -i -c 

и они все работают одинаково (и вы все еще используете код, указанный выше). Лично мне это не нравится, но я старомодный. Вы можете отключить его, если будете осторожны - один из способов - через переменную среды POSIXLY_CORRECT. Вы также можете организовать для getopt(), чтобы вернуть файлы, как если бы они были аргументами с кодом опции '\1' (Control-A).

+0

Это похоже на хорошее решение. На самом деле, я не могу уйти с оператором переключения все вместе? с чем-то вроде этого: в то время как ((х = Getopt (ARGC, ARGV, "МБВ:"!)) = -1) { \t \t если (х == 'б') \t \t \t get_b = истина; \t \t else if (x == 'i') \t \t \t get_i = true; \t \t else if (x == 'e') \t \t \t get_e = true; \t \t} – mjones

+0

Да, вы можете использовать цепочный набор операторов 'if' и' else if', но коммутатор обычно считается более понятным. –

+0

Кстати, я использую библиотечную функцию для переноса последнего цикла, поэтому моя программа заканчивается как «фильтр (argc, argv, optind, processfile)», который требует, чтобы флаги были глобальными. –

Смежные вопросы