Linux in function main

Передача аргументов в программу

Бывает, что данные в программу передаются из командной строки при ее вызове. Такие данные называются аргументами командной строки. Выглядит это так, например:

./a.out test.txt ls -lt /home/peter/

Здесь вызываются программы a.out (из текущего каталога) и ls (из одного каталога, указанного в переменной окружения PATH). Первая программа из командной строки получает одно слово — test.txt, вторая — два: -lt и /home/peter/.

Если программа написана на языке C, то при ее запуске управление сразу передается в функцию main() , следовательно, именно она получает аргументы командной строки, которые присваиваются ее переменным-параметрам.

До этого мы определяли функцию main() так, как-будто она не принимает никакие параметры и ничего не возвращает. На самом деле в языке C любая функция по-умолчанию (если не определено ничего иного) возвращает целое число. В этом можно убедиться. Если записать код таким образом:

, то ошибки при компиляции не возникнет (но будет предупреждение). То же самое будет, если записать int main() . Это доказывает, что функция по-умолчанию возвращает целое число, а не ничто ( void ). Хотя то, что возвращает функция всегда можно «переопределить», например, voidmain() или float main() .

При вызове программы из командной строки в нее всегда передается пара данных:

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

Само имя программы также считается. Например, если вызов выглядит так:

, то первый аргумент программы имеет значение 4, а массив строк определяется как .

Обратите внимание на терминологию, есть всего два аргумента программы (число и массив), но сколько угодно аргументов командной строки. Аргументы командной строки «преобразуются» в аргументы программы (в аргументы функции main() ).

Эти данные (число и указатель) передаются в программу даже тогда, когда она просто вызывается по имени без передачи в нее чего-либо: ./a.out. В таком случае первый аргумент имеет значение 1, а второй указывает на массив, состоящий всего из одной строки .

То, что в программу передаются данные, вовсе не означает, что функция main() должна их принимать. Если функция main() определена без параметров, то получить доступ к аргументам командной строки невозможно. Хотя ничего вам не мешает их передавать. Ошибки не возникнет.

Чтобы получить доступ к переданным в программу данным, их необходимо присвоить переменным. Поскольку аргументы сразу передаются в main() , то ее заголовок должен выглядеть таким образом:

В первой переменной (n) содержится количество слов, а во второй — указатель на массив строк. Часто второй параметр записывают в виде **arr . Однако это то же самое. Вспомним, что сам массив строк, содержит в качестве своих элементов указатели на строки. А в функцию мы передаем указатель на первый элемент массива. Получается, что передаем указатель на указатель, т.е. **arr .

#include int main(int argc, char **argv) { int i; printf("%d\n", argc); for (i=0; i  argc; i++) puts(argv[i]); }

Она выводит количество слов в командной строке при ее вызове и каждое слово с новой строки. Вызовите ее без аргументов командной строки и с аргументами.

В программе мы использовали переменные-параметры argc и argv. Принято использовать именно такие имена, но на самом деле они могут быть любыми. Лучше придерживаться этого стандарта, чтобы ваши программы были более понятны не только вам, но и другим программистам.

Практическое значение передачи данных в программу

Если у вас есть опыт работы в командной строке GNU/Linux, вы знаете, что у большинства команд есть ключи и аргументы. Например, при просмотре содержимого каталогов, копировании, перемещении в качестве аргументов указываются объекты файловой системы, над которыми выполняется команда. Особенности ее выполнения определяются с помощью ключей. Например, в команде

cp — это имя команды, -r — ключ, а ../les_1 и ../les_101 — аргументы команды.

Нередко в программы при их запуске передаются адреса файлов и «модификаторы» (это ключи) процесса выполнения программы.

Напишем программу, которая открывает указанные пользователем в командной строке файлы на запись или добавление и записывает (добавляет) туда одну и туже информацию, которую пользователь вводит с клавиатуры в процессе выполнения программы:

#include #include int main (int argc, char **argv)  int i, ch; FILE *f[5]; if (argc  3  if (strcmp(argv[1], "-w") != 0 && strcmp(argv[1], "-a") != 0) { puts("Первый параметр -w или -a"); return 2; } for (i=0; i  argc-2; i++){ f[i] = fopen(argv[i+2], argv[1]+1); if (f[i] == NULL) { printf("Файл %s нельзя открыть\n", argv[i+2]); return 3; } } while ((ch = getchar()) != EOF) for (i=0; i  argc-2; i++) putc(ch,f[i]); for (i=0; i  argc-2; i++) fclose(f[i]); return 0; }
  1. Создается массив из пяти файловых указателей. Следовательно можно одновременно открыть не более пяти файлов. Файловый указатель первого файла будет хранится в элементе массива f[0], второго — в f[1] и т.д.
  2. Проверяется количество аргументов командной строки. Их должно быть не меньше трех, т.к. первый — это имя программы, второй — режим открытия файла, третий — первый или единственный файл, в который будет производится запись. Поскольку программа позволяет открыть только пять файлов, то общее число аргументов командной строки не может быть больше семи. Поэтому если количество аргументов меньше 3 или больше 7, то программа завершается, т.к. оператор return приводит к выходу из функции, даже если после него есть еще код. Возвращаемое из функции значение неравное 0, может быть интерпретировано родительским процессом, как сообщение о том, что программа завершилась с ошибкой.
  3. Проверяется корректность второго аргумента командной строки. Если он не равен ни «-w», ни «-a», то условное выражение во втором if возвращает 1 (true). Функция strcmp() позволяет сравнивать строки и возвращает 0 в случае их равенства.
  4. В цикле for открываются файлы по указанным адресам, которые начинаются с третьего элемента массива argv. Именно поэтому к i прибавляется 2, чтобы получать элементы массива argv, начиная с третьего. Выражение argc-2 указывает на количество переданных имен файлов; т.к. в argc хранится общее число аргументов командной строки, первые два из которых не являются именами файлов.
  5. Выражение argv[1]+1 позволяет «вырезать» из строки «-w» (или «-a») подстроку «w» (или «a»), т.к. argv[1] по сути указатель на первый элемент строки. Прибавляя к указателю единицу, мы смещаем его к следующему элементу массива.
  6. Если файл отрыть не удается, то функция fopen() возвращает NULL. В таком случае программа завершается.
  7. Каждый символ, введенный пользователем с клавиатуры, записывается во все открытые файлы.
  8. В конце файлы закрываются.

Курс с решением части задач:
pdf-версия

Источник

Разбор опций командной строки в UNIX-подобных системах

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

POSIX

  • в имени программы должно быть не менее 2 и не более 9 символов;
  • имена программ должны быть написаны только строчными символами и цифрами;
  • имя опции должно быть простым буквенно-цифровым символом. Опции с множеством цифр запрещены;
  • все опции должны начинаться с символа «-«;
  • для опций без аргументов должны быть реализована возможность объединения опций (например foo -a -b -c и foo -abc);
  • аргумент опции должен отделятся от нее пробелом;
  • аргумент опции не может быть необязательным;
  • если опции требуется множество значений аргумента, они должны передаваться в виде строки, разделенные запятыми или разделителем;
  • опции должны идти перед операндами;
  • аргумент «—» указывает на окончание всех опций;
  • порядок опций не должен играть роли, кроме случаев когда опции взаимоисключающие, тогда побеждает последняя;
  • порядок аргументов может иметь значение;
  • программы читающие или записывающие именованные файлы, должны трактовать единственный аргумент «-» как стандартный ввод или стандартный вывод соответственно.

Длинные опции

  • каждая короткая опция должна иметь свой вариант длинной опции;
  • длинную опцию можно сократить до кратчайшей строки, обеспечивающей ее уникальность;
  • Аргументы длинной опции отделяются либо разделителем, либо знаком » ?» или «:» в зависимости от того найдена недействительная опция или пропущен обязательный аргумент опции, в переменной optopt будет находится обнаруженный недействительный символ.
    Следует заметить, что стандартная функция getopt() останавливается сразу как только найдет первый аргумент начинающийся не с символа «-«, GNU вариант функции просматривает в поисках опций, всю командную строку. Поведение GNU функции можно изменить (но это выходит за рамки статьи).

пример программы с использованием getopt()

  1. #include
  2. #include
  3. #include
  4. int main( int argc, char **argv)
  5. if (argc == 1) < // если запускаем без аргументов, выводим справку
  6. printf( «getopt test\n» );
  7. printf( «usage:\n» );
  8. printf( » opts -a n -b m -o s\n» );
  9. printf( «example:\n» );
  10. printf( » $ opts -a 323 -b 23 -o ‘-‘\n» );
  11. printf( » 323 — 23 = 300\n» );
  12. return 0;
  13. >
  14. char *opts = «a:b:o:» ; // доступные опции, каждая принимает аргумент
  15. int a, b; // тут храним числа
  16. char op; // а тут оператор
  17. int opt; // каждая следующая опция попадает сюда
  18. while ((opt = getopt(argc, argv, opts)) != -1) < // вызываем getopt пока она не вернет -1
  19. switch (opt)
  20. case ‘a’ : // если опция -a, преобразуем строку с аргументом в число
  21. a = atoi(optarg);
  22. break ;
  23. case ‘b’ : // тоже для -b
  24. b = atoi(optarg);
  25. break ;
  26. case ‘o’ : // в op сохраняем оператор
  27. op = optarg[0];
  28. break ;
  29. >
  30. >
  31. switch (op)
  32. case ‘+’ : // если опаратор + складываем, и т.д.
  33. printf( «%d + %d = %d\n» , a, b, a + b);
  34. break ;
  35. case ‘-‘ :
  36. printf( «%d — %d = %d\n» , a, b, a — b);
  37. break ;
  38. case ‘*’ :
  39. printf( «%d * %d = %d\n» , a, b, a * b);
  40. break ;
  41. case ‘/’ :
  42. printf( «%d / %d = %d\n» , a, b, a / b);
  43. break ;
  44. >
  45. return 0;
  46. >

getopt_long()

int getopt_long(int argc, char *argv[], const char *optstring, const struct option *longopts, int *longindex);

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

Структура option определена следующим образом:
struct option
const char *name;
int has_arg;
int *flag;
int val;
>

  • 0 — не принимает аргумент;
  • 1 — обязательный аргумент;
  • 2 — необязательный аргумент.

Пример программы с использованием getopt_long()

  1. #include
  2. #include
  3. #include
  4. #include
  5. void usage( char *name)
  6. printf( «usage: %s\n \ \t-h this message\n \ \t-c [config file]\n \ \t—help this message\n \ \t—config=config_file\n», name);
  7. return ;
  8. >
  9. int main ( int argc, char *argv[])
  10. int c;
  11. while (1)
  12. static struct option long_opt[] =
  13. < «help» , 0, 0, 'h' >,
  14. < «config» , 1, 0, 'c' >,
  15. >;
  16. int optIdx;
  17. if ((c = getopt_long(argc, argv, «c:h» , long_opt, &optIdx)) == -1)
  18. break ;
  19. switch ( c )
  20. case ‘h’ :
  21. usage(argv[0]);
  22. return (-1);
  23. case ‘c’ :
  24. printf( «option ‘c’ selected, filename: %s\n» , optarg);
  25. return (1);
  26. default :
  27. usage(argv[0]);
  28. return (-1);
  29. >
  30. >
  31. return (0);
  32. >

Заключение

В статье рассмотрены основы использования функций разбора аргументов командной строки в UNIX-подобных системах. Этот материал может быть более обширен, но любой заинтересовавшийся человек в состоянии узнать и изучить все тонкости самостоятельно.

Статья подготовлена по материалам книги Арнольда Роббинса «Linux программирование в примерах» ISBN 5-9579-0059-1

Источник

Читайте также:  How to start app in linux
Оцените статью
Adblock
detector