Команда eval в Bash и ее типичное использование

После прочтения man-страниц bash и относительно этогосообщение.

Я до сих пор не могу понять, что именноeval Команда делает и что было бы его типичным использованием. Например, если мы делаем:

bash$ set -- one two three  # sets $1 $2 $3
bash$ echo $1
one
bash$ n=1
bash$ echo ${$n}       ## First attempt to echo $1 using brackets fails
bash: ${$n}: bad substitution
bash$ echo $($n)       ## Second attempt to echo $1 using parentheses fails
bash: 1: command not found
bash$ eval echo \${$n} ## Third attempt to echo $1 using 'eval' succeeds
one

Что именно здесь происходит, и как знак доллара и обратная косая черта связаны с проблемой?

 Martin Wickman16 июн. 2012 г., 18:20
Для записи, вторая попытка работает.$($n) работает$n в скорлупе. Пытается запустить команду1 который не существует.
 jedwards16 июн. 2012 г., 19:26
@ Raze2dust: я не верю, что он предполагал, что он может работать с подоболочками, а скорее объясняет, почему 5-я команда из перечисленного OP не сработала.
 Dennis Williamson16 июн. 2012 г., 18:54
Вы должны знать оsecurity implications of using eval.
 Hari Menon16 июн. 2012 г., 18:26
@MartinWickman Но необходимо запуститьecho $1 в конце концов, не1, Я не думаю, что это можно сделать, используя подоболочки.

Ответы на вопрос(10)

Update: Some people say one should -never- use eval. I disagree. I think the risk arises when corrupt input can be passed to eval. However there are many common situations where that is not a risk, and therefore it is worth knowing how to use eval in any case. This ответ на стек объясняет риски eval и альтернативы eval. В конечном счете, пользователь должен определить, является ли eval безопасным и эффективным в использовании.

Башeval С помощью оператора вы можете выполнять строки кода, рассчитанные или полученные вашим bash-скриптом.

Возможно, самым простым примером была бы программа bash, которая открывает другой скрипт bash в виде текстового файла, читает каждую строку текста и используетeval выполнить их по порядку. Это по существу то же самое поведение, что и bash.source оператор, который будет использоваться, если только не потребовалось выполнить какое-либо преобразование (например, фильтрацию или подстановку) содержимого импортированного сценария.

Мне редко нужноeval, но я нашел полезным читать или записывать переменные, чьиnames содержались в строках, назначенных другим переменным. Например, выполнять действия с наборами переменных, сохраняя при этом небольшой объем кода и избегая избыточности.

eval концептуально просто Однако строгий синтаксис языка bash и порядок синтаксического анализа интерпретатора bash могут быть измененыeval кажутся загадочными и сложными в использовании или понимании. Вот основы:

The argument passed to eval is a string expression that is calculated at runtime. eval will execute the final parsed result of its argument as an actual line of code in your script.

Syntax and parsing order are stringent. If the result isn't an executable line of bash code, in scope of your script, the program will crash on the eval statement as it tries to execute garbage.

When testing you can replace the eval statement with echo and look at what is displayed. If it is legitimate code in the current context, running it through eval will work.

The following examples may help clarify how eval works...

Example 1:

eval statement in front of 'normal' code is a NOP
$ eval a=b
$ eval echo $a
b

В приведенном выше примере первыйeval Заявления не имеют цели и могут быть устранены.eval бессмысленно в первой строке, потому что в коде нет динамического аспекта, т. е. он уже проанализирован в последних строках кода bash, поэтому он будет идентичен обычному выражению кода в сценарии bash. 2-йeval тоже бессмысленно, потому что, хотя есть шаг разбора преобразования$a к его буквенному строковому эквиваленту нет косвенного обращения (например, нет ссылки через строковое значениеactual bash имя существительное или переменная сценария, поддерживаемая bash), поэтому он будет вести себя идентично строке кода безeval префикс.

Example 2:

Perform var assignment using var names passed as string values.
$ key="mykey"
$ val="myval"
$ eval $key=$val
$ echo $mykey
myval

Если бы вы былиecho $key=$val, результат будет:

mykey=myval

That, будучи конечным результатом разбора строки, это то, что будет выполняться eval, следовательно, результат оператора echo в конце ...

Example 3:

Adding more indirection to Example 2
$ keyA="keyB"
$ valA="valB"
$ keyB="that"
$ valB="amazing"
$ eval eval \$keyA=\$valA
$ echo $that
amazing

Выше немного сложнее, чем в предыдущем примере, в большей степени опираясь на порядок синтаксического анализа и особенности bash.eval строка будет примерно проанализирована внутри в следующем порядке(note the following statements are pseudocode, not real code, just to attempt to show how the statement would get broken down into steps internally to arrive at the final result).

 eval eval \$keyA=\$valA  # substitution of $keyA and $valA by interpreter
 eval eval \$keyB=\$valB    # convert '

Если предполагаемый порядок синтаксического анализа не объясняет, что eval делает достаточно, третий пример может описать синтаксический анализ более подробно, чтобы помочь прояснить, что происходит.

Example 4:

Discover whether vars, whose names are contained in strings, themselves contain string values.
a="User-provided"
b="Another user-provided optional value"
c=""

myvarname_a="a"
myvarname_b="b"
myvarname_c="c"

for varname in "myvarname_a" "myvarname_b" "myvarname_c"; do
    eval varval=\$varname
    if [ -z "$varval" ]; then
        read -p "$varname? " $varname
    fi
done

На первой итерации:

varname="myvarname_a"

Bash разбирает аргументeval, а такжеeval видит буквально это во время выполнения:

eval varval=\$myvarname_a

Следующиеpseudocode попытки проиллюстрироватьhow Bash интерпретирует приведенную выше строкуreal код, чтобы получить окончательное значение, выполненноеeval, (следующие строки описания, а не точный код bash):

1. eval varval="\$" + "$varname"      # This substitution resolved in eval statement
2. .................. "$myvarname_a"  # $myvarname_a previously resolved by for-loop
3. .................. "a"             # ... to this value
4. eval "varval=$a"                   # This requires one more parsing step
5. eval varval="User-provided"        # Final result of parsing (eval executes this)

После того, как весь разбор завершен, результат - это то, что выполняется, и его эффект очевиден, демонстрируя, что в этом нет ничего особенно загадочногоeval сама по себе, и сложность вparsing своего аргумента.

varval="User-provided"

Оставшийся код в приведенном выше примере просто проверяет, является ли значение, присвоенное $ varval, нулевым, и, если это так, запрашивает у пользователя значение.

+ name-strings to real vars by eval eval $keyB=$valB # substitution of $keyB and $valB by interpreter eval that=amazing # execute string literal 'that=amazing' by eval

Если предполагаемый порядок синтаксического анализа не объясняет, что eval делает достаточно, третий пример может описать синтаксический анализ более подробно, чтобы помочь прояснить, что происходит.

Example 4:

Discover whether vars, whose names are contained in strings, themselves contain string values.
a="User-provided"
b="Another user-provided optional value"
c=""

myvarname_a="a"
myvarname_b="b"
myvarname_c="c"

for varname in "myvarname_a" "myvarname_b" "myvarname_c"; do
    eval varval=\$$varname
    if [ -z "$varval" ]; then
        read -p "$varname? " $varname
    fi
done

На первой итерации:

varname="myvarname_a"

Bash разбирает аргументeval, а такжеeval видит буквально это во время выполнения:

eval varval=\$$myvarname_a

Следующиеpseudocode попытки проиллюстрироватьhow Bash интерпретирует приведенную выше строкуreal код, чтобы получить окончательное значение, выполненноеeval, (следующие строки описания, а не точный код bash):

1. eval varval="\$" + "$varname"      # This substitution resolved in eval statement
2. .................. "$myvarname_a"  # $myvarname_a previously resolved by for-loop
3. .................. "a"             # ... to this value
4. eval "varval=$a"                   # This requires one more parsing step
5. eval varval="User-provided"        # Final result of parsing (eval executes this)

После того, как весь разбор завершен, результат - это то, что выполняется, и его эффект очевиден, демонстрируя, что в этом нет ничего особенно загадочногоeval сама по себе, и сложность вparsing своего аргумента.

varval="User-provided"

Оставшийся код в приведенном выше примере просто проверяет, является ли значение, присвоенное $ varval, нулевым, и, если это так, запрашивает у пользователя значение.

Вы спрашивали о типичных целях.

Одна распространенная жалоба на использование сценариев оболочки заключается в том, что вы (предположительно) не можете передавать по ссылке, чтобы получить значения из функций.

Но на самом деле, через "eval", выcan передать по ссылке. Вызываемый может передать список переменных назначений для оценки вызывающим. Он передается по ссылке, потому что вызывающая сторона может указать имя (имена) результирующей (ых) переменной (ей) - см. Пример ниже. Результаты ошибок могут быть переданы обратно стандартным именам, таким как errno и errstr.

Вот пример передачи по ссылке в bash:

#!/bin/bash
isint()
{
    re='^[-]?[0-9]+

Вывод выглядит так:

[1] var=1
errstr=Error: non-integer argument to iadd var A B
errno=329
[2] var=1 (unchanged after error)
[3] var=2 (successfully changed)

Есть почтиunlimited ширина полосы в этом текстовом выходе! И существует больше возможностей, если используются несколько выходных строк: например, первая строка может использоваться для присвоения переменных, вторая для непрерывного «потока мысли», но это выходит за рамки этого поста.

[[ $1 =~ $re ]] } #args 1: name of result variable, 2: first addend, 3: second addend iadd() { if isint ${2} && isint ${3} ; then echo "$1=$((${2}+${3}));errno=0" return 0 else echo "errstr=\"Error: non-integer argument to iadd $*\" ; errno=329" return 1 fi } var=1 echo "[1] var=$var" eval $(iadd var A B) if [[ $errno -ne 0 ]]; then echo "errstr=$errstr" echo "errno=$errno" fi echo "[2] var=$var (unchanged after error)" eval $(iadd var $var 1) if [[ $errno -ne 0 ]]; then echo "errstr=$errstr" echo "errno=$errno" fi echo "[3] var=$var (successfully changed)"

Вывод выглядит так:

[1] var=1
errstr=Error: non-integer argument to iadd var A B
errno=329
[2] var=1 (unchanged after error)
[3] var=2 (successfully changed)

Есть почтиunlimited ширина полосы в этом текстовом выходе! И существует больше возможностей, если используются несколько выходных строк: например, первая строка может использоваться для присвоения переменных, вторая для непрерывного «потока мысли», но это выходит за рамки этого поста.

Мне нравится & quot; оценка вашего выражения еще один раз перед выполнением & quot; ответьте, и хотели бы уточнить с другим примером.

var="\"par1 par2\""
echo $var # prints nicely "par1 par2"

function cntpars() {
  echo "  > Count: $#"
  echo "  > Pars : $*"
  echo "  > par1 : $1"
  echo "  > par2 : $2"

  if [[ $# = 1 && $1 = "par1 par2" ]]; then
    echo "  > PASS"
  else
    echo "  > FAIL"
    return 1
  fi
}

# Option 1: Will Pass
echo "eval \"cntpars \$var\""
eval "cntpars $var"

# Option 2: Will Fail, with curious results
echo "cntpars \$var"
cntpars $var

Любопытные результаты в варианте 2 заключаются в том, что мы передали бы 2 параметра следующим образом:

First Parameter: "value Second Parameter: content"

Как это для счетчика интуитивно? Дополнительныйeval это исправлю.

Адаптированы изhttps://stackoverflow.com/a/40646371/744133

Оператор eval указывает оболочке принять аргументы eval в качестве команды и выполнить их через командную строку. Это полезно в ситуации как ниже:

В вашем скрипте, если вы определяете команду в переменную, а затем хотите использовать эту команду, тогда вы должны использовать eval:

/home/user1 > a="ls | more"
/home/user1 > $a
bash: command not found: ls | more
/home/user1 > # Above command didn't work as ls tried to list file with name pipe (|) and more. But these files are not there
/home/user1 > eval $a
file.txt
mailids
remote_cmd.sh
sample.txt
tmp
/home/user1 >
Решение Вопроса

eval принимает строку в качестве аргумента и оценивает ее так, как если бы вы ввели эту строку в командной строке. (Если вы передаете несколько аргументов, они сначала объединяются с пробелами между ними.)

${$n} это синтаксическая ошибка в bash. Внутри фигурных скобок у вас может быть только имя переменной с некоторыми возможными префиксами и суффиксами, но вы не можете иметь произвольный синтаксис bash и, в частности, вы не можете использовать расширение переменных. Есть способ сказать & # x201C; значение переменной, имя которой находится в этой переменной & # x201D ;, хотя:

echo ${!n}
one

$(…) выполняет команду, указанную в круглых скобках в подоболочке (то есть в отдельном процессе, который наследует все параметры, такие как значения переменных из текущей оболочки), и собирает его выходные данные. Такecho $($n) работает$n в виде команды оболочки и отображает ее вывод. поскольку$n оценивает1, $($n) пытается запустить команду1, которого не существует.

eval echo \${$n} запускает параметры, переданныеeval, После расширения параметрыecho а также${1}, Такeval echo \${$n} запускает командуecho ${1}.

Обратите внимание, что большую часть времени вы должны использовать двойные кавычки вокруг подстановок переменных и командных подстановок (то есть в любое время$): "$foo", "$(foo)". Always put double quotes around variable and command substitutionsЕсли только вы не знаете, что вам нужно оставить их. Без двойных кавычек оболочка выполняет разбиение поля (то есть разделяет значение переменной или вывод команды на отдельные слова), а затем обрабатывает каждое слово как шаблон подстановочного знака. Например:

$ ls
file1 file2 otherfile
$ set -- 'f* *'
$ echo "$1"
f* *
$ echo $1
file1 file2 file1 file2 otherfile
$ n=1
$ eval echo \${$n}
file1 file2 file1 file2 otherfile
$eval echo \"\${$n}\"
f* *
$ echo "${!n}"
f* *

eval не используется очень часто. В некоторых оболочках наиболее распространенным способом является получение значения переменной, имя которой неизвестно до времени выполнения. В bash это необязательно благодаря${!VAR} синтаксис.eval все еще полезно, когда вам нужно создать более длинную команду, содержащую операторы, зарезервированные слова и т. д.

 17 июн. 2012 г., 06:57
@ Konos5 & quot; проанализирован дважды & quot; немного вводит в заблуждение. Некоторым людям может показаться, что это связано с трудностью указания аргумента в виде буквенной строки в Bash, который защищен от различных расширений.eval просто берет код в строке и оценивает его по обычным правилам. Технически, это даже не правильно, потому что есть несколько угловых случаев, в которых Bash изменяет синтаксический анализ, чтобы даже не выполнять расширения аргументов eval - но это очень туманный кусок, о котором, я сомневаюсь, кто-нибудь знает.
 16 июн. 2012 г., 21:59
@ Konos5 Я бы не стал использоватьeval eval, Я не помню, чтобы когда-либо чувствовал потребность. Если вам действительно нужно дваeval проходит, используйте временную переменную, отладку будет легче:eval tmp="\${$i}"; eval x="\${$tmp}".
 16 июн. 2012 г., 21:41
@ Konos5 Какой комментарий?eval получает строку (которая сама по себе может быть результатом анализа и анализа) и интерпретирует ее как фрагмент кода.
 kstratis16 июн. 2012 г., 21:22
Что касается моего комментария выше, сколько «проходит» Eval делает?
 kstratis16 июн. 2012 г., 21:51
Под ответом Raze2dust я оставил комментарий. Теперь я склонен полагать, что eval в основном используется для разыменования. Если я наберу eval echo \ $ {$ n}, я получу его. Однако, если я наберу echo \ $ {$ n}, я получу \ $ {1}. Я полагаю, что это происходит из-за двухпроходного eval 's' разбор. Теперь мне интересно, что произойдет, если мне понадобится утроить разыменование с помощью дополнительного объявления i = n. В этом случае согласно Raze2dust мне просто нужно поставить дополнительный eval. Однако я считаю, что должен быть лучший способ ... (он может быть легко загроможден)

По моему опыту, «типичный» Использование eval предназначено для запуска команд, которые генерируют команды оболочки для установки переменных среды.

Возможно, у вас есть система, которая использует набор переменных среды, и у вас есть скрипт или программа, которая определяет, какие из них следует установить, и их значения. Каждый раз, когда вы запускаете скрипт или программу, он запускается в разветвленном процессе, поэтому все, что он делает непосредственно с переменными среды, теряется при выходе. Но этот скрипт или программа может отправлять команды экспорта в stdout.

Без eval вам нужно будет перенаправить стандартный вывод во временный файл, создать временный файл и затем удалить его. С eval вы можете просто:

eval "$(script-or-program)"

Обратите внимание, что цитаты важны. Возьмите этот (надуманный) пример:

# activate.sh
echo 'I got activated!'

# test.py
print("export foo=bar/baz/womp")
print(". activate.sh")

$ eval $(python test.py)
bash: export: `.': not a valid identifier
bash: export: `activate.sh': not a valid identifier
$ eval "$(python test.py)"
I got activated!
 05 нояб. 2014 г., 17:13
Есть примеры распространенных инструментов, которые делают это? Сам инструмент имеет средство для создания набора команд оболочки, которые можно передать в eval?
 05 нояб. 2014 г., 22:58
@Joakim Я не знаю ни одного инструмента с открытым исходным кодом, который бы делал это, но он использовался в некоторых частных сценариях в компаниях, где я работал. Я просто снова начал использовать эту технику с xampp. Apache .conf файлы расширяют переменные среды, записанные${varname}, Я считаю удобным использовать идентичные файлы .conf на нескольких разных серверах с несколькими параметрами, параметризованными переменными среды. Я отредактировал / opt / lampp / xampp (который запускает apache), чтобы сделать этот вид eval с помощью скрипта, который копается в системе и выводит bashexport операторы для определения переменных для файлов .conf.
 26 дек. 2015 г., 06:13
Это должен быть принятый ответ IMO, он объяснил, для чего используется eval, и показывает практический пример. Спасибо :)
 08 апр. 2015 г., 16:39
@Anthony Sottile Я вижу, что вы отредактировали ответ, добавив кавычки около $ (скрипт или программа), сказав, что они были важны при выполнении нескольких команд. Можете ли вы привести пример - следующее работает отлично с командами, разделенными точкой с запятой в stdout файла foo.sh: echo & apos; #! / Bin / bash & apos; & GT; foo.sh; echo 'echo' echo -n a; эхо -n б; echo -n c "" & GT; & GT; foo.sh; chmod 755 foo.sh; eval $ (./ foo.sh). Это производит ABC на стандартный вывод. Запуск ./foo.sh производит: echo -n a; эхо -n б; эхо-н с
 05 нояб. 2014 г., 23:08
@Joakim Альтернативой будет иметь скрипт для генерации каждого из затронутых файлов .conf из шаблона, основываясь на том же поиске. Одна вещь, которая мне больше нравится в моем пути, это то, что запуск apache без прохождения / opt / lampp / xampp не использует устаревшие сценарии вывода, а скорее не запускается, потому что переменные среды расширяются до нуля и создают недопустимые директивы.

Просто думайте о eval как о «оценке вашего выражения еще один раз перед выполнением» & quot;

eval echo \${$n} становитсяecho $1 после первого тура оценки. Три изменения, чтобы заметить:

The \$ became $ (The backslash is needed, otherwise it tries to evaluate ${$n}, which means a variable named {$n}, which is not allowed) $n was evaluated to 1 The eval disappeared

Во втором туре это в основномecho $1 который может быть непосредственно выполнен.

Такeval <some command> сначала оценим<some command> (Под оценкой здесь я подразумеваю замену переменных, замену экранированных символов на правильные и т. д.), а затем снова запускаю результирующее выражение.

eval используется, когда вы хотите динамически создавать переменные или читать выходные данные программ, специально предназначенных для чтения таким образом. Увидетьhttp://mywiki.wooledge.org/BashFAQ/048 Например. Ссылка также содержит некоторые типичные способы, которымиeval используется, и риски, связанные с этим.

 17 июн. 2012 г., 17:03
@ Konos5 Слева направо - правильный способ разбора цитат и обратной косой черты. Первый\\  получая один обратный слеш. затем\$ приносящий один доллар И так далее.
 16 июн. 2012 г., 21:34
eval eval echo \\\${\${$i}} сделаем тройную разыменование. Я не уверен, есть ли более простой способ сделать это. Также,\${$n} работает отлично (печатаетone) на моей машине ..
 17 июн. 2012 г., 16:21
@ Konos5 Думайте в том же духе - первый` escapes the second one, and the third `избегает$ после этого. Так становится\${${n}} после одного раунда оценки
 16 июн. 2012 г., 19:24
Как примечание для первой пули,${VAR} синтаксисis допускается и предпочтительнее, когда есть какая-либо двусмысленность$VAR == $V, с последующимAR или же$VAR == $VA с последующимR). ${VAR} эквивалентно$VAR, На самом деле, это имя переменной$n это не разрешено.
 16 июн. 2012 г., 22:45
@ Konos5echo \\\${\${$i}} печать\${${n}}. eval echo \\\${\${$i}} эквивалентноecho \${${n}}`` and prints ${1}. eval eval echo \\\ $ {\ $ {$ i}} `эквивалентноeval echo ${1} и печатаетone.

В вопросе:

who | grep $(tty | sed s:/dev/::)

выводит ошибки, утверждая, что файлы a и tty не существуют. Я понял, что это означает, что tty не интерпретируется перед выполнением grep, а вместо этого bash передает tty в качестве параметра grep, который интерпретирует его как имя файла.

Существует также ситуация вложенного перенаправления, которая должна обрабатываться соответствующими скобками, которые должны указывать дочерний процесс, но bash примитивно является разделителем слов, создавая параметры для отправки в программу, поэтому круглые скобки не сопоставляются первыми, а интерпретируются как видел.

Я получил конкретный с grep, и указал файл в качестве параметра вместо использования канала. Я также упростил базовую команду, передавая выходные данные из команды в виде файла, чтобы трубопровод ввода-вывода не был вложенным:

grep $(tty | sed s:/dev/::) <(who)

работает хорошо.

who | grep $(echo pts/3)

не очень желательно, но устраняет вложенные трубы и также хорошо работает.

В заключение, bash, похоже, не любит вложенный pipping. Важно понимать, что bash не является программой новой волны, написанной рекурсивно. Вместо этого, bash - это старая программа 1,2,3, которая была дополнена функциями. В целях обеспечения обратной совместимости первоначальный способ интерпретации никогда не менялся. Если бы bash был переписан для соответствия первым скобкам, сколько ошибок было бы внесено во сколько программ bash? Многие программисты любят быть загадочными.

Изначально я намеренно никогда не изучал, как использовать eval, потому что большинство людей будут рекомендовать держаться подальше от него, как от чумы. Однако недавно я обнаружил случай использования, который заставил меня помазать лицо за то, что я не узнал его раньше.

Если у вас есть задания cron, которые вы хотите запустить для тестирования в интерактивном режиме, вы можете просмотреть содержимое файла с помощью команды cat, а затем скопировать и вставить задание cron для его запуска. К сожалению, это касается прикосновения мыши, что является грехом в моей книге.

Допустим, у вас есть работа cron по адресу /etc/cron.d/repeatme с содержимым:

*/10 * * * * root program arg1 arg2

Вы не можете выполнить это как скрипт со всем мусором перед ним, но мы можем использовать cut, чтобы избавиться от всего мусора, обернуть его в подоболочку и выполнить строку с помощью eval

eval $( cut -d ' ' -f 6- /etc/cron.d/repeatme)

Команда cut распечатывает только 6-е поле файла, разделенное пробелами. Затем Eval выполняет эту команду.

В качестве примера я использовал задание cron, но концепция заключается в том, чтобы отформатировать текст из stdout, а затем оценить этот текст.

Использование eval в этом случае небезопасно, потому что мы точно знаем, что будем оценивать заранее.

Я недавно должен был использоватьeval заставить несколько расширений скобок быть оценены в порядке, в котором я нуждался. Bash делает несколько расширений скобок слева направо, так

xargs -I_ cat _/{11..15}/{8..5}.jpg

расширяется до

xargs -I_ cat _/11/8.jpg _/11/7.jpg _/11/6.jpg _/11/5.jpg _/12/8.jpg _/12/7.jpg _/12/6.jpg _/12/5.jpg _/13/8.jpg _/13/7.jpg _/13/6.jpg _/13/5.jpg _/14/8.jpg _/14/7.jpg _/14/6.jpg _/14/5.jpg _/15/8.jpg _/15/7.jpg _/15/6.jpg _/15/5.jpg

но мне нужно было сделать второе расширение скобки первым, давая

xargs -I_ cat _/11/8.jpg _/12/8.jpg _/13/8.jpg _/14/8.jpg _/15/8.jpg _/11/7.jpg _/12/7.jpg _/13/7.jpg _/14/7.jpg _/15/7.jpg _/11/6.jpg _/12/6.jpg _/13/6.jpg _/14/6.jpg _/15/6.jpg _/11/5.jpg _/12/5.jpg _/13/5.jpg _/14/5.jpg _/15/5.jpg

Лучшее, что я мог придумать, чтобы сделать это, было

xargs -I_ cat $(eval echo _/'{11..15}'/{8..5}.jpg)

Это работает, потому что одинарные кавычки защищают первый набор скобок от расширения во время анализаeval командная строка, оставляя их расширяться с помощью подоболочки, вызываемойeval.

Может быть какая-то хитрая схема, включающая вложенные фигурные скобки, которая позволяет этому происходить за один шаг, но если я слишком стар и глуп, чтобы это увидеть.

Ваш ответ на вопрос