Відповіді:
Спрощена причина є наявність одного символу: space.
Розширення дужок не обробляють проміжки (без котирування).
У {...}
списку потрібні пробіли (без котирування).
Більш детальна відповідь - як оболонка розбирає командний рядок .
Перший крок для розбору (розуміння) командного рядка - це поділ його на частини.
Ці частини (як правило, називаються словами або лексемами) є результатом ділення командного рядка на кожен мета-символ із посилання :
- Розбиває команду на маркери, які розділені фіксованим набором мета-символів: SPACE, TAB, NEWLINE,;, (,), <,>, | та &. Типи лексем включають слова, ключові слова, перенаправлення вводу / виводу та крапки з комою.
Мета-символи: spacetabenter;,<>|і &.
Після розщеплення слова можуть мати тип (як розуміється під оболонкою):
LC=ALL ...
LC=ALL echo
LC=ALL echo "hello"
LC=ALL echo "hello" >&2
Тільки якщо "рядок дужок" (без пробілів чи мета-символів) є одним словом (як описано вище) і не цитується , він є кандидатом на "Розширення дужки". Пізніше проводиться перевірка внутрішньої структури.
Таким чином, це: {ls,-l}
кваліфікується як "Розширення Brace", щоб стати ls -l
або як ( first word
або argument
в bash, zsh відрізняється).
$ {ls,-l} ### executes `ls -l`
$ echo {ls,-l} ### prints `ls -l`
Але це не буде: {ls ,-l}
. Bash розділить spaceі проаналізує рядок у вигляді двох слів: {ls
і ,-l}
що призведе до command not found
(аргумент ,-l}
втрачено):
$ {ls ,-l}
bash: {ls: command not found
Ваш рядок: {ls;echo hi}
не стане "Brace розширенням" через два мета-символи ;та 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
;
і }
. { ls;}
працює як крапка з комою - це вже мета-символ.
Блок {
- це ключове слово оболонки, тому він повинен відокремлюватися від наступного слова пробілом, тоді як у розгортанні дужок не повинно бути місця (якщо вам потрібно дужки розширити пробіл, вам слід уникнути цього:) echo {\ ,a}{b,c}
.
Ви можете використовувати розширення дужок на початку команди:
{ls,.} # expands to "ls ."
Ви не можете використовувати його для розширення до блоку, однак, як розбір команд групування відбувається перед розширеннями:
echo {'{ ls','.;}'} # { ls .;}
{'{ ls','.;}'} # bash: { ls: No such file or directory
Це знає, перевіривши синтаксис командного рядка. Таким же чином відомо, що в виразі echo echo
до першого відлуння слід ставитися як до команди, а до другого - як до параметра першого відлуння.
У bash це дуже просто, оскільки { cmd; }
має бути пробіл і крапка з комою. Однак, наприклад, в zsh вони не потрібні, але все ж, проаналізувавши контекст {}
оболонки, можна сказати, що слід робити з її вмістом.
Розглянемо наступне:
alias 1..3=date
{ 1..3; } #in bash
{1..3} #in zsh
Обидва повертають поточну дату, але
echo {1..3}
повертається, 1 2 3
оскільки оболонка знає {}
в аргументі для команди echo
, тому її слід розширити.
{
після чого котирування без котирування не починає розширення дужок у bash.
{
. Простір без котирування не може бути ніде, оскільки оболонка розбиває весь командний рядок на пробіли.
По-перше, складений дужок повинен бути самим словом і першим словом командного рядка:
echo { these braces are just words }
По-друге, окремі брекети не особливі (як ви бачите вище). Порожні дужки також не особливі:
echo {} # just the token {}: familiar from the find command
Все, що не має коми, також є лише самим собою
echo {abc} # just {abc}
Ось де починається дія.
echo {a,b} # braces disappear, a b results.
Отже, в основному для розгортання дужок нам потрібне одне слово (не розділене на поля в пробілі), усередині якого відбувається принаймні один екземпляр, {...}
всередині якого виникає принаймні одна кома.
Це , до речі, може бути першим словом у командному рядку:
{ls,-l} . # just "ls -l ."
{
трактуватися як список команд, якщо він з’являється на початку команди і як розширення дужок в іншому випадку, але я не впевнений.