Как расширить содержимое массива по его имени? [дубликат]

Вы можете использовать Here String с синтаксисом <<<:

ls | while IFS= read -r line
do
  name=$(sed 's/\(.*\)/\1.jpg/' <<< $line) && mv "$line" "$name"
done

Имейте в виду, что не рекомендуется анализировать выходные данные ls (или использовать нецитируемые переменные).

Существует также имя инструмента rename (в случае, если целью является просто переименовать файл):

rename -n 's/$/.jpg/' *

Снимите флаг -n, чтобы перейти от предварительного просмотра к фактическому переименованию.

1
08.03.2017, 13:44
3 ответа

Это возможно с eval :

$ declare -a array=( 1 2 3 4 )
$ echo "${array[@]}"
1 2 3 4
$ p=ay
$ tmp=arr$p
$ echo "$tmp"
array
$ echo "\${${tmp}[@]}"
${array[@]}
$ echo "newarray=(\"\${${tmp}[@]}\")"
newarray=("${array[@]}")
$ eval "newarray=(\"\${${tmp}[@]}\")"
$ echo "${newarray[@]}"
1 2 3 4
$

Команды, начинающиеся с echo, служат для иллюстрации, eval опасен.

Обратите внимание, что приведенное выше не сохраняет индексы массивов для разреженных массивов.

7
27.01.2020, 23:13

Косвенное расширение имеет некоторые исключения, и использование! в массивах - одно из исключений.

Из man bash:

Если первым символом параметра является восклицательный знак (!), Вводится уровень косвенного обращения к переменной . Bash использует значение переменной, образованной из оставшейся части параметра, в качестве имени переменной ; затем эта переменная расширяется, и это значение используется в остальной части замены, а не в значении самого параметра. Это называется косвенным раскрытием.

Исключением являются расширения $ {! Prefix *} и $ {! Name [@]} , описанные ниже. $ {! Prefix *} Префикс соответствия имен. Заменяется на имена переменных , имена которых начинаются с префикса, разделенного первым символом специальной переменной IFS.

Как описано в BASH FAQ06 , одно временное решение выглядит следующим образом:

arrA=("AA" "2" "4")
echo -e "array arrA contains: \c" && declare -p arrA
ref=arrA;
tmp=${ref}[@] #this can be adjusted to [1] , [2] etc to refer to particular array items
echo "Indirect Expansion Printing: ${!tmp}"

#Output
array arrA contains: declare -a arrA='([0]="AA" [1]="2" [2]="4")'
Indirect Expansion Printing: AA 2 4
2
27.01.2020, 23:13

bash 4.3 добавил поддержку ksh93-подобных namerefs.

Поэтому в bash-4.3 и выше вы можете сделать:

a0[5]=whatever
x=0
typeset -n var="a$x"
printf '%s\n' "${var[5]}"

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

bash скопировал ksh массивы с их неудобным дизайном. Сделать копию массива в bash сложно, вы можете использовать вспомогательную функцию типа:

copy_array() { # Args: <src_array_name> <dst_array_name>
  eval '
    local i
    '"$2"'=()
    for i in "${!'"$1"'[@]}"; do
      '"$2"'[$i]=${'"$1"'[$i]}
    done'
}

Для использования, например, как:

$ a0[5]=123
$ x=0
$ copy_array "a$x" var
$ typeset -p var
declare -a var=([5]="123")

kshbash, который копирует ksh) - единственная оболочка, где массивы являются разреженными (или являются ассоциативными массивами, ключи которых ограничены целыми положительными числами) (также единственные массивы с индексами, начинающимися с 0, а не с 1, или где $array неинтуитивно расширяется не до элементов, а до элемента с индексом 0). С другими оболочками все гораздо проще.

  • rc: array_copy = $array
  • fish: set array_copy = $array
  • csh: set array_copy = ($array:q)
  • zsh или yash: array_copy=("${array[@]}"}

Для косвенного копирования (где $var содержит имя исходного массива):

  • rc: eval array_copy = '$'$var
  • fish: eval set array_copy \$$var
  • csh: eval "set array_copy = (\$$${var}:q)"
  • zsh: array_copy=("${(@P)var}")
  • yash (or zsh): eval 'array_copy=("${'"$var"'[@]}")'
2
27.01.2020, 23:13

Теги

Похожие вопросы