Ну, это разворачивается один слой за один раз:
X{{a..c},{1..3}}Y
документировано как расширяются до X{a..c}Y
X{1..3}Y
(что X{A,B}Y
расширено XA
XB
с A
того {a..c}
и B
того {1..3}
), сам документировано , как расширяются до XaY
XbY
XcY
X1Y
X2Y
X3Y
.
Что может стоить документировать, так это то, что они могут быть вложенными (например, первое }
не закрывает первое {
там).
Я полагаю, что оболочки могли бы сначала разрешить внутренние скобки, например, действуя при каждом закрытии }
по очереди:
X{{a..c},{1..3}}
X{a,{1..3}}Y
X{b,{1..3}}Y
X{c,{1..3}}Y
( A{a..c}B
расширяется до AaB
AbB
AcB
, где A
есть X{
и B
есть ,{1..3}Y
)
X{a,1}Y
X{a,2}Y
X{a,3}Y
X{b,1}Y
X{b,2}Y
X{b,3}Y
X{c,1}Y
X{c,2}Y
X{c,3}Y
XaY
X1Y
XaY
Xa2
...
Но я не считаю, что это более интуитивно и бесполезно (см., Например, пример Кевина в комментариях), все равно будет некоторая двусмысленность в отношении порядка, в котором будут выполняться расширения, и это не так csh
(оболочка, которая ввела фигурную скобку). расширение в конце 70-х годов, в то время как {1..3}
форма пришла позже (1995) zsh
и {a..c}
еще позже (2004) из bash
) сделал это.
Обратите внимание, что csh
(с самого начала, см. Справочную страницу 2BSD (1979) ) действительно документировал тот факт, что расширения фигурных скобок могли быть вложенными, хотя явно не говорилось, как будут расширяться вложенные расширения фигурных скобок. Но вы можете посмотреть на csh
код 1979 года, чтобы увидеть, как это было сделано тогда. Посмотрите, как он явно обрабатывает вложение, и как оно разрешается, начиная с внешних фигурных скобок.
В любом случае, я не очень понимаю, как расширение {a..c},{1..3}
может иметь какое-то отношение. Там ,
оператор не является расширением фигурных скобок (так как он не находится внутри фигурных скобок), поэтому рассматривается как любой обычный символ.
/dev/{h,s}d{a..d}{1..4,}
. Теперь предположим, что вы хотите расширить его, чтобы включить/dev/null
и/dev/zero
. Если бы расширение скобки работало изнутри, это расширение было бы действительно раздражающим для построения. Но поскольку он работает извне, это довольно тривиально:/dev/{null,zero,{h,s}d{a..d}{1..4,}}
Вот краткий ответ. В первом выражении запятая используется в качестве разделителя, поэтому расширение в скобках является просто объединением двух вложенных подвыражений. Во втором выражении запятая сам по себе рассматривается как односимвольный подвыражению, поэтому выражения продукта будут сформированы.
Чего вам не хватало, так это определения того, как выполняются скобки-расширения. Вот три ссылки:
Более подробное объяснение приведено ниже.
Вы сравнили результат этого выражения:
к результату этого выражения:
Вы говорите, что это трудно объяснить, то есть что это нелогично. Чего не хватает, так это формального определения того, как обрабатываются скобки-расширения. Обратите внимание, что руководство по Bash не дает полного определения.
Я немного искал, но не смог найти отсутствующее (полное, формальное) определение. Итак, я пошел к исходному коду:
Источник содержит пару полезных комментариев. Во-первых, это общий обзор алгоритма расширения фигурных скобок:
Таким образом, формат токена расширения скобки следующий:
Основной точкой входа в расширение является функция,
brace_expand
которая называется следующим образом:Таким образом,
brace_expand
функция принимает строку, представляющую выражение расширения фигурной скобки, и возвращает массив развернутых строк.Комбинируя эти два наблюдения, мы видим, что значение amble расширено до списка строк, каждая из которых объединена в преамбуле. Затем метка раскладывается в список строк, и каждая строка в списке меток объединяется с каждой строкой в списке преамбул / амблей (т.е. формируется произведение двух списков). Но это не описывает, как обрабатываются amble и postamble. К счастью, есть комментарий, описывающий это также. Обрамление обрабатывается функцией, вызванной
expand_amble
определением, которой предшествует следующий комментарий:В другом месте кода мы видим, что BRACE_ARG_SEPARATOR определяется как запятая. Это проясняет, что amble - это список строк, разделенных запятыми, некоторые из которых также могут быть выражениями в скобках. Эти строки затем образуют один массив. Наконец, мы можем видеть , что после того, как
expand_amble
называетсяbrace_expand
функция затем вызывается рекурсивно на постамбула. Это дает нам полное описание алгоритма.Существуют и другие (неофициальные) ссылки, подтверждающие этот вывод.
Для одной ссылки, проверьте Bash Hackers Wiki . Раздел о комбинировании и вложении не совсем решает вашу проблему, но на странице есть синтаксис / грамматика расширения фигурных скобок, что, я думаю, отвечает на ваш вопрос. Синтаксис задается следующими шаблонами:
И разбор описывается следующим образом:
Для другой ссылки, взгляните на Руководство для начинающих Bash , в котором есть следующее:
Таким образом, для разбора выражений в фигурных скобках мы идем слева направо, расширяя каждое выражение и формируя последовательные продукты (относительно операции объединения строк).
Теперь давайте рассмотрим ваше первое выражение:
На языке вики Bash Hacker's это соответствует первой форме:
Там , где
N=2
,string1={a..c}
иstring2={1..3}
- внутренние скобки разложения выполняется первым , и каждый из них формы{<START>..<END>}
. В качестве альтернативы, мы можем сказать, что это выражение расширения скобки, которое состоит только из amble (без преамбулы или постамбла). Amble - это список, разделенный запятыми, поэтому мы просматриваем список по одному слоту за раз и выполняем дополнительные расширения, где это необходимо. Продукт не формируется, потому что нет смежных выражений (запятая используется в качестве разделителя).Теперь давайте посмотрим на ваше второе выражение:
На языке вики Bash Hacker's это выражение соответствует форме:
где постскриптум это подвыражение
,{1..3}
. В качестве альтернативы, мы можем сказать, что это выражение имеет amble ({a..c}
) и postamble (,{1..3}
).a b c
Амбл разворачивается в список, а затем каждая из них объединяется с каждой из строк в расширении постамбла. Этот пост обрабатывается рекурсивно: у него есть преамбула,
и ряд{1..3}
. Это расширено до списка,1 ,2 ,3
. Два списка,a b c
а,1 ,2 ,3
затем объединяются для формирования списка продуктовa,1 a,2 a,3 b,1 b,2 b,3 c,1 c,2 c,3
.Это может помочь дать псевдоалгебраическое описание того, как эти выражения анализируются, где скобки «[]» обозначают массивы, «+» обозначает конкатенацию массива, а «*» обозначает декартово произведение (относительно конкатенации).
Вот как раскрывается первое выражение (один шаг на строку):
А вот как расширяется второе выражение:
источник
Мое понимание таково:
Внутренние скобки разрешаются первыми (как всегда), что превращает
в
Поскольку
,
внутри фигурных скобок он просто разделяет элементы фигурных скобок.Но в случае
,
не в фигурных скобках , т.е. это обычный символ вызывает фигурные скобки перестановки с обоего сторон.источник
{a..c}
или разрешаетсяa,b,c
илиa b c
зависит от влажности и Доу-Джонса? Ухоженная.{{a..c},{1..3}}
это так же, как{a,b,c,1,2,3}
, то не должно{{a..c}.{1..3}}
быть так же, как{a,b,c.1,2,3}
? Это, конечно, не так.,
является символом разделения расширения скобки,.
нет. Почему обычный персонаж должен приводить к таким же результатам, как специальный?c.1
это элемент скобки. Но в является якорем для скрепляющих расширений на левой и правой стороны . С наружными брекетами используются для расширения распорки , так как их содержание имеет формат расширение распорки, с их не потому , что их содержание не имеет тот же формат.{a..c}.{1..3}
.
,
.
{{a..c},{1..3}}
превращается{a,b,c,1,2,3}
затем несколько запятых только появились междуa
,b
иc
. Почему они не появляются так же, как с{a..c}.{1..3}
? Комментарий @kubanczyk примерно такой же: если запятые появляются там вот так, как мы узнаем, когда расширение генерирует запятые, а когда нет? Ответ, конечно, в том, что он никогда не генерирует запятые сам по себе, он генерирует список слов. Так что ничто не превращается в{a,b,c,1,2,3}
или{a,b,c.1,2,3}
.