Linux программирование в примерах
#define GETOPT_HELP_OPTION_DECL \"help", no_argument, 0, GETOPT_HELP_CHAR#define GETOPT_VERSION_OPTION_DECL \"version", no_argument, 0, GETOPT_VERSION_CHAR#define case_GETOPT_HELP_CHAR \case GETOPT_HELP_CHAR: \usage(EXIT_SUCCESS); \break;#define case_GETOPT_VERSION_CHAR(Program_name, Authors) \case GETOPT_VERSION_CHAR: \version_etc(stdout, Program_name, PACKAGE, VERSION, Authors); \exit(EXIT_SUCCESS); \break;Результатом этого кода является печать сообщения об использовании утилиты для
и печать информации о версии для--help. Обе опции завершаются успешно («Успешный» и «неудачный» статусы завершения описаны в разделе 9.1.5.1 «Определение статуса завершения процесса».) Поскольку в Coreutils входят десятки утилит, имеет смысл вынести за скобки и стандартизовать как можно больше повторяющегося кода.--versionВозвращаясь к
:env.с174 environ = dummy_environ;175 environ[0] = NULL;176177 if (!ignore_environment)178 for (; *envp; envp++)179 putenv(*envp);180181 optind = 0; /* Принудительная реинициализация GNU getopt. */182 while ((optc = getopt_long(argc, argv, "+iu:", longopts, NULL)) != -1)183 if (optc == 'u')184 putenv(optarg); /* Требуется GNU putenv. */185186 if (optind !=argc && !strcmp(argv[optind], "-")) /* Пропустить опции */187 ++optind;188189 while (optind < argc && strchr(argv[optind], '=')) /* Установитьпеременные окружения * /190 putenv(argv[optind++]);191192 /* Если программа не указана, напечатать переменные окружения и выйти. */193 if (optind == argc)194 {195 while (*environ)196 puts (*environ++);197 exit(EXIT_SUCCESS);198 }Строки 174–179 переносят существующие переменные в новую копию окружения. В глобальную переменную
помещается указатель на пустой локальный массив. Параметрenvironподдерживает доступ к первоначальному окружению.envpСтроки 181–184 удаляют переменные окружения, указанные в опции
. Программа осуществляет это, повторно сканируя командную строку и удаляя перечисленные там имена. Удаление переменных окружения основывается на обсуждавшейся ранее особенности GNU-u: при вызове с одним лишь именем переменной (без указанного значения)putenv()удаляет ее из окружения.putenv()После опций в командной строке помещаются новые или замещающие переменные окружения. Строки 189–190 продолжают сканирование командной строки, отыскивая установки переменных окружения в виде '
'.<i>имя</i>=<i>значение</i>По достижении строки 192, если в командной строке ничего не осталось, предполагается, что
печатает новое окружение и выходит из программы. Она это и делает (строки 195–197).envЕсли остались аргументы, они представляют имя команды, которую нужно вызвать, и аргументы для передачи этой новой команде. Это делается с помощью системного вызова
(строка 200), который замещает текущую программу новой. (Этот вызов обсуждается в разделе 9.1.4 «Запуск новой программы: семействоexecvp()»; пока не беспокойтесь о деталях.) Если этот вызов возвращается в текущую программу, он потерпел неудачу. В таком случаеexec()выводит сообщение об ошибке и завершает программу.env200 execvp(argv[optind], &argv[optind]);201202 {203 int exit_status = (errno == ENOENT ? 127 : 126);204 error(0, errno, "%s", argv[optind]);205 exit(exit_status);206 }207 }Значения кода завершения
и126(определяемые в строке 203) соответствуют стандарту POSIX.127означает, что программа, которую127попыталась запустить, не существует. (execvp()означает, что файл не содержит записи в каталоге.)ENOENTозначает, что файл существует, но была какая-то другая ошибка.1262.5. Резюме
• Программы на С получают аргументы своей командной строки через параметры
иargc. Функцияargvпредоставляет стандартный способ для последовательного разбора опций и их аргументов GNU версияgetopt()предоставляет некоторые расширения, agetopt()иgetopt_long()дает возможность легкого разбора длинных опций.getopt_long_only()• Окружение представляет собой набор пар '
', который каждая программа наследует от своего родителя. Программы могут по прихоти своего автора использовать для изменения своего поведения переменные окружения, в дополнение к любым аргументам командной строки. Для получения значений переменных окружения, изменения их значений или удаления существуют стандартные процедуры (<i>имя</i>=<i>значение</i>,getenv(),setenv()иputenv()). При необходимости можно получить доступ ко всему окружению через внешнюю переменнуюunsetenv()или через третий аргументenvironфункцииchar **envp. Последний способ не рекомендуется.main()