Упрощенная причина является наличие одного символа: space.
Расширения скобок не обрабатывают (не заключенные в кавычки) пробелы.
{...}
Список потребностей (ООН-цитируемый) пространства.
Более подробный ответ - как оболочка анализирует командную строку .
Первый шаг для разбора (понимания) командной строки - это разделить ее на части.
Эти части (обычно называемые словами или токенами) являются результатом разделения командной строки каждого метасимвола по ссылке :
- Разбивает команду на токены, разделенные фиксированным набором метасимволов: SPACE, TAB, NEWLINE,;, (,), <,>, | и &. Типы токенов включают слова, ключевые слова, перенаправители ввода / вывода и точки с запятой.
Мета-символы: spacetabenter;,<>|а &.
После разбиения слова могут иметь тип (как понимается оболочкой):
- Предварительные назначения команд:
LC=ALL ...
- команда
LC=ALL echo
- аргументы
LC=ALL echo "hello"
- Перенаправление
LC=ALL echo "hello" >&2
Расширение скобки
Только если «строка скобок» (без пробелов или метасимволов) является одним словом (как описано выше) и не заключена в кавычки , она является кандидатом на «Расширение скобок». Больше проверок выполнено на внутренней структуре позже.
Таким образом, это: {ls,-l}
квалифицируется как «расширение скобки», чтобы стать ls -l
, как first word
или argument
(в bash, zsh отличается).
$ {ls,-l} ### executes `ls -l`
$ echo {ls,-l} ### prints `ls -l`
Но это не будет {ls ,-l}
. Bash разделит spaceи проанализирует строку как два слова: {ls
и ,-l}
которая вызовет a command not found
(аргумент ,-l}
потерян):
$ {ls ,-l}
bash: {ls: command not found
Ваша строка: {ls;echo hi}
не станет «расширением скобок» из-за двух метасимволов ;и space.
Он будет разбит на следующие три части: {ls
новая команда: echo
hi}
. Поймите, что ;запускает начало новой команды. Команда {ls
не будет найдена, и следующая команда напечатает hi}
:
$ {ls;echo hi}
bash: {ls: command not found
hi}
Если он помещен после какой-либо другой команды, он все равно начнет новую команду после ;:
$ echo {ls;echo hi}
{ls
hi}
Список
Одна из «составных команд» является «Brace List» (мои слова): { list; }
.
Как видите, он определяется пробелами и закрытием ;
.
Пробелы и ;нужны потому, что оба {
и }
являются «зарезервированными словами ».
И поэтому, чтобы быть узнаваемым как слова, должны быть окружены метасимволами (почти всегда:) space.
Как описано в пункте 2 связанной страницы
- Проверяет первый токен каждой команды, чтобы узнать, является ли он ...., {или (, тогда команда на самом деле является составной командой.
Ваш пример: {ls;echo hi}
это не список.
Требуется закрытие ;и один пробел (как минимум) после {. Последний }определяется закрытием ;.
Это список { ls;echo hi; }
. И это { ls;echo hi;}
тоже (менее часто используемый, но действительный) (спасибо @choroba за помощь).
$ { ls;echo hi; }
A-list-of-files
hi
Но в качестве аргумента (оболочка знает разницу) команды, она вызывает ошибку:
$ echo { ls;echo hi; }
bash: syntax error near unexpected token `}'
Но будьте осторожны с тем, что, по вашему мнению, интерпретирует оболочка:
$ echo { ls;echo hi;
{ ls
hi
{
это интерпретируется как список команд, если он появляется в начале команды, а в противном случае как расширение скобки, но я не уверен.