Упрощенная причина является наличие одного символа: 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
{это интерпретируется как список команд, если он появляется в начале команды, а в противном случае как расширение скобки, но я не уверен.