Почему пробелы между параметрами и параметрами не указываются?

16

Например:

xargs -n 1

такой же как

xargs -n1

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

Это также происходит со многими другими утилитами Linux.

Как это называется в Linux? Все ли утилиты поддерживают сокращенную форму (но никогда не документируют ее на странице руководства)?

J.Joe
источник
1
12.1.2.a - часть истории; Клянусь, здесь уже есть хороший вопрос по этому поводу, но я еще не нашел его.
2
@drewbenn другой вопрос, о котором вы думаете, мог быть моим: unix.stackexchange.com/q/188046/41515

Ответы:

12

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

opt_h=0     # default value
opt_a=""

while getopts 'a:h' opt; do
    case $opt in
        h)  opt_h=1 ;;
        a)  opt_a="$OPTARG" ;;
    esac
done

echo "h: $opt_h"
echo "a: $opt_a"

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

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

Запуск это:

$ bash test.sh -h -a hello
h: 1
a: hello

$ bash test.sh -h -ahello
h: 1
a: hello

$ bash test.sh -hahello
h: 1
a: hello

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

В этом примере есть только один сложный случай. Разбор обычно останавливается на первой не-опции, поэтому если у вас есть вещи в командной строке , которая выглядит как варианты:

$ bash test.sh -a hello -world
test.sh: illegal option -- w
test.sh: illegal option -- o
test.sh: illegal option -- r
test.sh: illegal option -- l
test.sh: illegal option -- d
h: 0
a: hello

Следующее решает, что:

$ bash test.sh -a hello -- -world
h: 0
a: hello

-- сигналы конец параметров командной строки, а -worldбит остается для программы , чтобы сделать все , что хочет с (это в одной из позиционных переменных).

То есть, кстати, как вы удаляете файл, который имеет тире в начале своего имени файла с rm .

РЕДАКТИРОВАТЬ :

Утилиты, написанные на C, getopt()(объявленные в unistd.h), работают примерно так же. На самом деле, насколько нам известно, bashфункция getoptsможет быть реализована с помощью вызова функции библиотеки Cgetopt() . Perl, Python и другие языки имеют похожие библиотеки синтаксического анализа командной строки, и, скорее всего, они выполняют их анализ аналогичным образом.

Некоторые из этих getoptи getoptподобных библиотечных подпрограмм также обрабатывают «длинные» опции. Им обычно предшествует double-dash ( --), а длинные опции, которые принимают аргументы, часто делают это после знака равенства, например, --block-size=SIZEопция [некоторых реализаций] duутилиты (которая также позволяет-B SIZE указывать одно и то же).

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

РЕДАКТИРОВАТЬ : Действительно старые инструменты, такие как ddи tarутилиты, имеют опции без черточек перед ними. Это чисто по историческим причинам и для обеспечения совместимости с программным обеспечением, которое полагается на них для работы именно таким образом. tarУтилита получила возможность принимать варианты с прочерками в более поздние времена. Руководство BSD для tarвызова опций старого стиля для «связанных флагов».

Кусалананда
источник
Эта функция может показаться легкой для реализации в скриптах bash. Но я думаю, что большинство утилит написаны на C (затем скомпилированы в двоичные файлы), а не bash. Почему эти утилиты реализуют эту функцию?
Дж. Джо,
@ J.Joe Потому что они называют getopt()(объявлено в unistd.h), что делает то же самое.
Кусалананда
2
Да, вы правы. Ссылка . Это также решает еще одну загадку, что варианты могут быть объединены -a -b=== -ab
J.Joe
1
Необязательные аргументы для флагов создают двусмысленность, поэтому их нельзя объединять (если -aесть необязательный аргумент, -abэто не то же самое, что -a -b). GNU getopt не останавливает обработку флагов, когда встречает не-флаг: вместо этого (по умолчанию), вместо этого он перемещает флаги в начало argv.
ilkkachu
@ilkkachu Спасибо за это разъяснение. Я могу обновить свой ответ позже.
Кусалананда
4

xargsявляется одной из утилит POSIX. Как прокомментировал @drewbenn, POSIX документирует поведение при разборе опций для большинства своих утилит для сопоставления getoptс некоторыми допусками для других реализаций, говоря в 12.1 Синтаксис аргумента утилиты :

В этом разделе описывается синтаксис аргументов стандартных утилит и вводится терминология, используемая в POSIX.1-2008 для описания аргументов, обрабатываемых утилитами.

В POSIX.1-2008 специальная нотация используется для описания синтаксиса аргументов утилиты. Если не указано иное , все описания утилит используют это обозначение, которое иллюстрируется этим примером (см. Простые команды XCU ):

и в заключение

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

В POSIX (помните, что он охватывает только наиболее часто используемые утилиты), есть исключения, которые передают операнды, которые будут опциями в других утилитах, в качестве либо позиционных параметров, либо параметров со специальным синтаксисом :

POSIX допускает необязательные значения параметров:

Опциональные аргументы отображаются отдельно от своих опций <blank>символами, за исключением случаев, когда опционный аргумент заключен в'[' и ']'обозначении , чтобы указать , что это не является обязательным.

Не знаю, какие утилиты POSIX используют эту функцию. Ncurses ticи infocmpутилиты используют функцию для уровней из-v (информативном / отладке) варианта.

Конкретный вопрос, о котором вы спрашивали, подробно описан в оставшейся части этого абзаца и состоит из нескольких строк.

До POSIX некоторые реализации psпринимаемых опций без начального дефиса. В описании POSIX это не упоминается в описании утилиты или в обосновании синтаксиса:

Помимо POSIX, существуют реализации с длинными опциями (например, GNU getopt_long или X Toolkit ), использующие различные способы разделения или присоединения значения опции к опции. Например, пунктуация может использоваться:

--option=value
--option value

В зависимости от реализации, двойная тире может / не может использоваться, чтобы отличить длинные опции от коротких (getopt): lynx и X Toolkit используют одну черту; getopt_longНапример, GNU использует двойную черту. Также+ может использоваться, чтобы указать, что опция отменена.

В описании POSIX не упоминается ни одно из них, но вы наверняка столкнетесь с ними.

Томас Дики
источник
Является ли -option=valueдолжен быть --option=value(длинный формат-варианта, два тира в начале , а не один)?
J.Joe
Некоторые устаревшие утилиты используют длинные опции (-option), но они в значительной степени устарели для новых сценариев и программ. Используйте одну черту для коротких опций, которые обрабатываются getopt. Почти все новые скрипты и программы используют длинные опции двойного тире. Многие также поддерживают эквиваленты коротких опций с одной чертой для наиболее часто используемых. Длинные опции делают код сценария намного более самодокументированным, требуя меньше комментариев.
DocSalvager