2015-01-01 4 views
1

У меня есть теоретический вопрос о синтаксисе Bash.
Я бегу Bash 4.3.11 (1) в Linux Ubuntu 14.04.Одиночные кавычки в расширении истории (bash)

На официальном сайте GNU: Bash official web (GNU)
в подразделе 9.3.1. он говорит:

строка

Обратитесь к самой последней команде, предшествующей текущей позиции в списке истории, начиная с строки.

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

Однако при описании , цитируя в подразделе 3.1.2., Мы можем прочитать в пункте 3.1.2.2. Далее:

Ограждающие символы в одинарных кавычках («'») сохраняет буквальное значения каждого символа в кавычках.

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

Таким образом, выражение, подобное !'some text', должно искать в списке истории Bash для самой последней команды, начиная с 'some text'.

Однако пробел между some и text нарушается, когда я пишу это в моем терминале, так как следующее сообщение об ошибке показано ниже:

Баш: "некоторые из них: событие не найдено

Является ли это поведение ошибкой в ​​реализации оболочки, или я не понимаю правила расширения Bash для этого примера?

+2

Я не знаю ничего официального, но я собираюсь пойти с таким же ответом, что rici дает [здесь] (http://stackoverflow.com/a/25021905/258523), который в основном состоит в том, что анализ синтаксиса не очень умный (несмотря на то, что в документах, в которых речь идет об обработке расширения истории, цитируются строки в строках, которые он извлекает из истории). Или, может быть, более точно, расширение истории является предварительным анализом и не очень умным. –

+0

@EtanReisner: Большое спасибо (ссылка ** rici ** была для меня очень осветляющей). – pablo1977

+1

@EtanReisner: Да, что я там сказал. Расширение истории - такой клоч. Если вы укажете строку string, строка будет прервана пробелом или двоеточием; цитирование * не * учтено. Или, другими словами, расширение истории происходит до того, как bash даже смотрит на цитаты. Если вы укажете соответствие подстроки (!? String?), Правила меняются. Затем строка заканчивается только символом? или новой строки. – rici

ответ

2

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

Баш страница руководства это состояние, что расширение истории «выполняется сразу же после полной строки читается, перед перерывами оболочки в слова» (курсив мой), в то время как руководство Баш упоминает, что расширение истории обеспечивается от Библиотека истории. Это основная причина большинства различий в расширении истории: расширение истории работает на необработанных непроверенных входах без какой-либо помощи от токенизатора bash и в основном выполняется с внешней библиотекой, которая не зависит от bash. Поскольку входной ток bash является нетривиальным, неудивительно, что относительно простые правила синтаксического анализа, используемые во время расширения истории, являются лишь приблизительным приближением к реальному синтаксическому анализу.

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

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

Вопрос, поднятый этим вопросом, несколько отличается, поскольку речь идет о следующем этапе разбора истории. Как только установлено, что конкретный символ является символом расширения истории, тогда необходимо проанализировать «событие», которое следует; как указано в руководстве bash, событие может принимать несколько форм, один из которых - !string, представляющий самую последнюю команду, начинающуюся с «string».

Подразумевается, что эта форма будет использоваться только тогда, когда не применяется ни одна другая форма, которая означает, что string не может начинаться с цифры или -, !, # или ?. Он также не может начинаться с пробела или = (поскольку те будут препятствовать расширению истории) и в некоторых случаях ( или " (который может ингибировать расширение истории). И, наконец, он не может начинаться с ^, $, % или *, который будет интерпретироваться как слово целеуказатель (от события по умолчанию, что предыдущая команда).

bash manual не уточняет, что завершает string. это пол -документ ed в history library manual, в котором упоминается, что строка поиска истории (или «событие», как она вызывается в руководстве bash) заканчивается пробелом, : или любым из символов в переменной конфигурации истории history_search_delimiter_chars. (Для записи bash в настоящее время (v4.3) устанавливает эту переменную в ";&()|<>".)

Как указано ранее, при принятии решения о признании символа расширения истории учитывается цитирование; как выясняется, если расширение истории происходит внутри строки с двумя кавычками, то закрывающая двойная кавычка также считается символом разделителя поиска в истории. И это, насколько мне известно, представляет собой весь список символов, который разделит !string.

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

Разбор истории расширения подстроки - !?string? - совершенно иная. Эта строка может быть прервана только ? или новой линией. (Как сказано в руководстве Баша, задняя ? является необязательной, если заканчиваться символом новой строки.)

После того, как символ расширения истории был признан и история поиск строка была определена, то может возникнуть необходимость расколоть извлечение истории в слова. Опять же, руководство по bash немного небрежно об угловых случаях, когда говорится, что «строка разбита на слова так же, как и у Bash, так что несколько слов, окруженных кавычками, считаются одним словом».

Педант заметил бы, что «так же, как это делает Баш», это не то же самое, что сказать «точно так, как это сделал бы Бэш», а на самом деле вторая часть предложения буквальна: несколько слов, окруженных котировки считаются одним словом , даже если котировки не соответствуют котировкам. Например, строка:

command "$(echo " foo bar ")" 

считается библиотекой истории состоит из следующих пяти слов:

0. command 
1. "$(echo " 
2. foo 
3. bar 
4. ")" 

хотя Баш синтаксического анализ был бы совсем иным. Напротив, bash и библиотека истории соглашаются на разбор

command "$(echo ' foo bar ')" 

как два слова.

+0

Очень хороший ответ. Большое спасибо. – pablo1977

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