Есть ли правильно определенный способ разделения аргументов команд в C?

Например, рассмотрим звонок:

>routine -h -s name -t "name also" -u 'name as well'

Вернет ли это 8 аргументов или больше? Есть ли определенный стандарт относительно того, как они анализируются? Где бы это было расположено?

ПРИМЕЧАНИЕ. Меня интересует не код для этого, а применимые правила или стандарты. Я не считаю чтение исходного кода где-либо документацией стандарта, которая, как я полагаю, должна где-то находиться.


person Jiminion    schedule 04.06.2015    source источник
comment
Предполагая, что > - это ваше приглашение, если вы введете ввод, я думаю, что ' не будет совпадать с ", и поэтому оболочка может вызвать ошибку   -  person Eregrith    schedule 04.06.2015
comment
Меня интересует содержание самого argv [], а не то, как с ними обращаться /   -  person Jiminion    schedule 04.06.2015
comment
Почему бы просто не распечатать содержимое argv? Например. for (int a = 0; a < argc; ++a) printf("argv[%d] = %s\n", a, argv[a]);   -  person Some programmer dude    schedule 04.06.2015
comment
Их обрабатывает синтаксический анализ аргументов командной строки. Если вас это не интересует, о чем ваш вопрос?   -  person n. 1.8e9-where's-my-share m.    schedule 04.06.2015
comment
В случае нормальной оболочки программа никогда не увидит аргументов; оболочка отклонит команду из-за несоответствия " и '.   -  person Keith Thompson    schedule 04.06.2015
comment
@JoachimPileborg Потому что это просто указывает на конкретную систему. Мне интересно знать, существует ли стандарт. (Похоже, я конфабулирую правила синтаксического анализа оболочки для синтаксического анализа аргументов, которые представляют собой просто обработанные оболочкой сущности, загруженные в argv [] .....   -  person Jiminion    schedule 04.06.2015
comment
@KeithThompson Этот пример не следует воспринимать буквально. Поддерживает ли оболочка разделители в одинарных и двойных кавычках? Принимает ли он и другие разделители?   -  person Jiminion    schedule 04.06.2015
comment
Если несовпадение " и ' в вашем примере было опечаткой, я предлагаю вам отредактировать вопрос, чтобы исправить это. Как оболочка преобразует командную строку в массив argv - это другой вопрос, чем анализ массива argv после запуска программы.   -  person Keith Thompson    schedule 04.06.2015
comment
Если ваш вопрос касается того, как стандартная оболочка интерпретирует командную строку, чтобы предоставить утилите argc и argv, то этот вопрос не имеет ничего общего с C, а заголовок и тег вводят в заблуждение. Просьба уточнить. (Если вы считаете, что эту работу выполняет служебная программа или вызов exec, значит, ваша модель неверна.)   -  person rici    schedule 04.06.2015
comment
@Jiminion: Ну, я постарался ответить на неявный вопрос. Надеюсь, поможет.   -  person rici    schedule 04.06.2015
comment
Ваш вопрос все еще неясен. Когда вы спрашиваете, как анализируются аргументы, я обычно предполагаю, что вы говорите о чем-то, что, например, связывает аргумент name с предшествующей опцией -s. Я думаю, вы пытаетесь спросить, как строка командной строки разбивается на элементы массива, на который ссылается argv. Спроси об этом.   -  person Keith Thompson    schedule 04.06.2015


Ответы (3)


Используемая оболочка отвечает за анализ командной строки и соответствующий вызов exec*(). См. Документацию по конкретной рассматриваемой оболочке, чтобы узнать о ее правилах, и ее исходный код, чтобы увидеть, как она анализирует командную строку.

person Ignacio Vazquez-Abrams    schedule 04.06.2015
comment
Думаю, это ближе всего к тому, что я ищу. Но документация по exec () немного расплывчата относительно того, что она делает. Например, не уверен, какие разделители он распознает. - person Jiminion; 04.06.2015
comment
exec*() ничего не делает. Командная строка должна анализироваться оболочкой. - person Ignacio Vazquez-Abrams; 04.06.2015

Стандартная командная оболочка - это язык программирования, действиями которого (в основном) являются вызовы «утилит», которые являются исполняемыми программами. Задача, которую выполняет оболочка, - настроить стандартную среду для вызова утилиты, которая включает в себя:

  • Выяснение, какой исполняемый файл соответствует вызываемой утилите;

  • Назначение файловых дескрипторов stdin, stdout и stderr для утилиты соответствующим потокам;

  • Создание вектора аргументов argv и передача его вызванной утилите;

  • Настройка environ global утилиты, доступ к которой утилита может получить через getenv стандартную библиотечную функцию;

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

Например, /usr/bin и "this is not a sentence" являются буквальными значениями в языке оболочки. Кавычки вокруг второго из них не являются частью стоимости; они являются частью синтаксиса языка для буквальных строк. (Язык оболочки позволяет записывать многие буквальные строки без кавычек, а также включает сложный язык выражений, так что не все строки в двойных кавычках являются литералами, но в простом случае строка в кавычках концептуально не отличается от строки в кавычках в C .)

Базовый синтаксис и семантика стандартизированы Posix. Многие широко используемые языки оболочки в основном соответствуют этому стандарту. Почти все имеют расширения; некоторые (если не большинство) не полностью совместимы даже с базовым стандартом, если не включены определенные параметры. (Например, для bash, вызывая его с аргументом командной строки --posix.) Однако, как правило, соблюдаются основные принципы, и чтение приведенной выше ссылки Posix предоставит хороший обзор. Включает полную грамматику.

В целом процедура следующая:

  • Оболочка разбивает командную строку на «слова».
  • Некоторые слова «расширены», возможно, заменены ноль или более слов.
  • Некоторые слова интерпретируются как перенаправление файлового дескриптора; другие как назначения переменных среды.
  • Если результатом является определенный синтаксис оболочки, он выполняется. В противном случае первое слово интерпретируется либо как имя функции оболочки, либо как встроенная команда, либо как внешняя утилита.
  • Если команда разрешается во внешнюю утилиту, слова из командной строки (кроме тех, которые уже используются как перенаправления и назначения) помещаются в вектор argv, и утилита вызывается.

Это намного сложнее, но это основная модель.

Вызов утилиты выполняется с использованием одной из exec* семейства стандартных библиотечных функций, которая принимает в качестве аргументов:

  • Путь к исполняемому файлу
  • Вектор указателей на строки с нулевым завершением, который будет вектором argv
  • Вектор с нулевым завершением указателей на строки формы name=value, который будет environ глобальным.

Затем вызов exec вызывает внешнюю утилиту. Он копирует вектор аргументов и список окружения в адресное пространство утилиты, но не изменяет и не проверяет значения иначе, кроме проверки того, что общий размер двух списков не превышает некоторый системный предел.


Остальная часть этого ответа относится к тому, как сама утилита (может или должна) анализировать вектор аргументов, который она получает.

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

Начнем с того, что правила Posix (в основном) выполняются стандартная функция Posix getopt. Эти рекомендации предполагают, что необязательные аргументы (с - флагами) предшествуют всем позиционным аргументам.

Однако не все утилиты Posix соответствуют этим предложениям, и часто встречаются утилиты, которые «переставляют» аргументы, позволяя параметрам следовать позиционным аргументам. Этот механизм (в основном) реализован версией getopt для Gnu. . Кроме того, Gnu определяет (и предлагает использовать) getopt_long функция, которая позволяет использовать многозначные параметры, инициированные с --.

Во всех случаях, как анализируются необязательные аргументы флага, зависит от того, определена ли опция как принимающая аргумент или нет. Так

-s1 word

можно разобрать как:

  • If -s takes an argument:
    • option -s with argument "1"
    • позиционный аргумент "слово"
  • If -s does not take an argument and -1 is a valid flag not taking an argument
    • option -s
    • вариант -1
    • позиционный аргумент "слово"
  • If -s does not take an argument and -1 does take an argument:
    • option -s
    • вариант -1 с аргументом "слово"

В дополнение к вышеперечисленному, существуют также команды, которые принимают «длинные параметры», начинающиеся с одного дефиса (и, таким образом, не позволяют объединить короткие параметры в одно слово). Это стиль, используемый TCL, за которым следуют многие команды графического интерфейса. Этот стиль можно проанализировать с помощью функции GNU getopt_long_only (см. Предыдущую ссылку).

person rici    schedule 04.06.2015
comment
@Jiminion: Верно. Оболочка разделит команду на 8 слов, и это то, что вы найдете в argv. Если вы хотите знать, как оболочка разбивает команды на слова, это задокументировано Posix (и различными оболочками, которые могут иметь дополнительные функции). Если вы не используете оболочку (например, вызываете какую-то exec* функцию), тогда вы предоставляете argv, и никаких изменений не происходит. - person rici; 04.06.2015

POSIX определяет функцию getopt() и _ 2_ (обычно встроенная в оболочку) для анализа аргументов командной строки.

Стандарт допускает только однобуквенные имена параметров, поэтому он не поддерживает ваш пример:

routine -h -s1 name -s2 "name also" -s3 "name as well"

ПРИМЕЧАНИЕ. В вашем вопросе в конце командной строки указано "name as well'. Это будет отклонено оболочкой еще до того, как routine увидит свои аргументы из-за несоответствия кавычек. Я предполагаю, что это была просто опечатка.

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

person Keith Thompson    schedule 04.06.2015
comment
Нет. Не интересует разбор аргументов. Просто содержимое argv []. Я думаю, что ответ о том, что это зависит от exec (), является наиболее правильным, но документация по exec очень расплывчата. - person Jiminion; 04.06.2015
comment
@Jiminion: Тогда обновите свой вопрос. В заголовке есть слово "синтаксический анализ". Если вас интересует только содержание argv, вы должны указать это в вопросе. Недостаточно разъяснить свои намерения в комментариях; сам вопрос должен быть ясным. - person Keith Thompson; 04.06.2015