Использование переменных с формой выражения-последовательности ({<numFrom>..<numTo>}
) из расширение скобок работает только в ksh
и zsh
, но, к сожалению, не работает в bash
(и (в основном) только оболочки POSIX-функций, такие как dash
, не поддерживают раскрытие скобок вообще, поэтому следует вообще избегать раскрытия скобок с /bin/sh
).
Учитывая ваши симптомы, я предполагаю, что вы используете bash
, где вы можете использовать только литералы в выражениях последовательности (например, {1..3}
); из руководства (выделено мной ):
Раскрытие фигурных скобок выполняется перед любыми другими раскрытиями, и все символы, характерные для других раскрытий, сохраняются в результате.
Другими словами: во время вычисления выражения в скобках ссылки на переменные еще не были развернуты (разрешены); Таким образом, интерпретация литералов, таких как $var1
и $var2
, как чисел в контексте выражения последовательности невозможна, поэтому выражение в фигурных скобках считается недействительным и не раскрываемым.
Обратите внимание: однако ссылки на переменные расширяются, а именно на более позднем этапе общего расширения; в данном случае литеральным результатом является одно слово '{1..4}'
- нераскрытое фигурное выражение с развернутыми значениями переменных.
Несмотря на то, что форма списка раскрытия фигурных скобок (например, {foo,bar)
) раскрывается таким же образом, последующее раскрытие переменных не является проблемой, поскольку заранее не требуется интерпретация элементов списка; например {$var1,$var2}
правильно приводит к двум словам 1
и 4
.
Что касается почему переменные нельзя использовать в выражениях последовательности: исторически, список форма раскрытия скобок была первой, и когда позже была введена форма выражения последовательности, порядок раскрытия уже был фиксированным.
Общий обзор раскрытия фигурных скобок см. в этот ответ.
Обходные пути
Примечание. Обходные пути сосредоточены на выражениях числовой последовательности, как в вопросе; обходной путь на основе eval
также демонстрирует использование переменных с менее распространенными выражениями последовательности символов, которые создают диапазоны английских букв (например, {a..c}
для получения a b c
).
Возможен обходной путь на основе seq
, как показано в ответе Джеймсона.
Небольшое предостережение: seq
не является утилитой POSIX, но она есть на большинстве современных Unix-подобных платформ.
Чтобы немного улучшить его, используя параметр -f
seq
для предоставления строки формата в стиле printf
и демонстрируя двухзначное заполнение нулями:
seq -f '%02.f.txt' $var1 $var2 | xargs ls # '%02.f'==zero-pad to 2 digits, no decimal places
Обратите внимание: чтобы сделать его полностью надежным — в случае, если результирующие слова содержат пробелы или символы табуляции — вам нужно использовать встроенные кавычки:
seq -f '"%02.f a.txt"' $var1 $var2 | xargs ls
ls
затем видит 01 a.txt
, 02 a.txt
, ... с правильно сохраненными границами аргументов.
Если вы хотите сначала надежно собрать полученные слова в массив Bash, например, ${words[@]}
:
IFS=$'\n' read -d '' -ra words < <(seq -f '%02.f.txt' $var1 $var2)
ls "${words[@]}"
Ниже приведены чистые обходные пути Bash:
ограниченный обходной путь, использующий только функции Bash, заключается в использовании eval
:
var1=1 var2=4
# Safety check
(( 10#$var1 + 10#$var2 || 1 )) 2>/dev/null || { echo "Need decimal integers." >&2; exit 1; }
ls $(eval printf '%s\ ' "{$var1..$var2}.txt") # -> ls 1.txt 2.txt 3.txt 4.txt
Аналогичную технику можно применить к выражению последовательности символов;
var1=a var2=c
# Safety check
[[ $var1 == [a-zA-Z] && $var2 == [a-zA-Z] ]] || { echo "Need single letters."; exit 1; }
ls $(eval printf '%s\ ' "{$var1..$var2}.txt") # -> ls a.txt b.txt c.txt
Примечание:
- Предварительно выполняется проверка, чтобы убедиться, что
$var1
и $var2
содержат десятичные целые числа или отдельные английские буквы, что затем делает безопасным использование eval
. Как правило, использование eval
с непроверенными входными данными представляет собой угрозу безопасности, поэтому лучше избегать использования eval
.
- Учитывая, что выходные данные из
eval
должны передаваться без кавычек в ls
здесь, чтобы оболочка разделяла выходные данные на отдельные аргументы посредством разделения слов, это работает только в том случае, если результирующие имена файлов содержат нет встроенных пробелов или других метасимволов оболочки.
более надежный, но более громоздкий обходной путь для чистого Bash для использования массива для создания эквивалентных слов:
var1=1 var2=4
# Emulate brace sequence expression using an array.
args=()
for (( i = var1; i <= var2; i++ )); do
args+=( "$i.txt" )
done
ls "${args[@]}"
- Этот подход не несет угрозы безопасности, а также работает с результирующими именами файлов со встроенными метасимволами оболочки, такими как пробелы.
- Пользовательские приращения могут быть реализованы путем замены
i++
, например, i+=2
для шага с шагом 2.
- Реализация нулевого заполнения потребует использования
printf
; например, следующим образом:
args+=( "$(printf '%02d.txt' "$i")" ) # -> '01.txt', '02.txt', ...
person
mklement0
schedule
03.11.2015
.txt
) в расширении. - person mklement0   schedule 03.11.2015