Имя переменной типа массив оценки Bash

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

Это решение требует создания двух отдельных сценариев.

Этот первый сценарий ответственен за то, что на самом деле переместил файлы в конечный диск.

md5_map_file="<absolute-path-to-a-temporary-file>"

# Given a single line from the md5 map file, list
# only the path from that line.
get_file()
{
  echo $2
}

# Given an md5, list the filename from the md5 map file
get_file_from_md5()
{
  # Grab the line from the md5 map file that has the
  # md5 sum passed in and call get_file() with that line.
  get_file `cat $md5_map_file | grep $1`
}

file=$1

# Compute the md5
sum=`md5sum $file`

# Get the new path for the file
new_file=`get_file_from_md5 $sum`

# Make sure the destination directory exists
mkdir -p `dirname $new_file`
# Move the file, prompting if the move would cause an overwrite
mv -i $file $new_file

Второй сценарий создает файл карты md5, используемый первым сценарием, и затем называет первый сценарий на каждом файле в конечном диске.

# Do not put trailing /
src="<absolute-path-to-source-drive>"
dst="<absolute-path-to-destination-drive>"
script_path="<absolute-path-to-the-first-script>"
md5_map_file="<same-absolute-path-from-first-script>"


# This command searches through the source drive
# looking for files.  For every file it finds,
# it computes the md5sum and writes the md5 sum and
# the path to the found filename to the filename stored
# in $md5_map_file.
# The end result is a file listing the md5 of every file
# on the source drive
cd $src
find . -type f -exec md5sum "{}" \; > $md5_map_file

# This command searches the destination drive for files and calls the first
# script for every file it finds.
cd $dst
find . -type f -exec $script_path '{}' \; 

В основном, что продолжается, эти два сценария similuate ассоциативный массив с $md5_map_file. Во-первых, все md5s для файлов на исходном диске вычисляются и хранятся. Связанный с md5s относительные пути от корня диска. Затем для каждого файла на конечном диске вычисляется md5. Используя этот md5, ищется путь того файла на исходном диске. Файл на конечном диске затем перемещен для соответствия пути файла на исходном диске.

Существует несколько протестов с этим сценарием:

  • Это предполагает, что каждый файл в $dst находится также в $src
  • Это не удаляет каталогов из $dst, только перемещает файлы. Я в настоящее время не могу думать о безопасном способе сделать это автоматически
6
20.05.2011, 18:48
6 ответов

Я решил его; последний пример должен быть похожим на это:

eval varAlias=\${"myvar"$varname[@]}
for varItem in ${varAlias[@]}
do
    echo $varItem
done
1
27.01.2020, 20:23

В Вашем ответе, varAlias не массив, таким образом, можно сделать for varItem in $varAlias который просто делает разделение слова. Из-за этого, если какой-либо из Ваших элементов исходного массива будет включать пробелы, то их будут рассматривать как отдельные слова.

Можно сделать скалярную косвенность как это: a=42; b=a; echo ${!b}.

Можно сделать косвенность к массиву скаляров как это:

$ j=42; k=55; m=99
$ a=(j k m)
$ echo ${!a[1]}
55

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

См. также BashFAQ/006.

2
27.01.2020, 20:23

Самая простая форма для расширения параметра: ${parameter}.
Используя фигурные скобки в запутанном случае лучший путь.

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

#!/bin/bash -x
myvarA=( "variable  A1" "variable  A2" )
varname="A"

eval varAlias=( '"${myvar'${varname}'[@]}"' )
eval varAlias=( \"\${myvar${varname}[@]}\" ) # both works
for varItem in "${varAlias[@]}" # double quote and `@' is needed
do
    echo "$varItem"
done
8
27.01.2020, 20:23

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

, Что я имею в виду, то, что следующее:

eval varAlias=\${"myvar"$varname[@]}

должен быть изменен на:

eval varAlias=(\${"myvar"$varname[@]})

можно проверить это путем взятия обоих чехлов и выполнения:

echo ${#varAlias[@]}

В исходном случае вы доберетесь 1 в круглой скобке вы получите фактическое число или элементы в исходном массиве. В обоих случаях мы в основном создаем новый массив.

0
27.01.2020, 20:23

Похоже, вы пытаетесь косвенно ссылаться на массив от индекса другого.

Вы можете сделать что-то вроде:

arr_one[0]=arr_two[@]

оттуда можно сделать:

cmd "${!arr_one[0]}"

... Чтобы косвенно ссылаться на полное расширение «$ {Arr_two [@]}» . Как можно ближе к тому, как я могу сказать, дальше нет прямого метода индексации. Например «$ {! Arr_one [0] [1]}" не работает, как я надеюсь, (по крайней мере, не в bash ) Но вы можете сделать «$ {! Arr_One [0] 1: 1}» и аналогично нарезанию расширения, как вы можете любой другой массив. Конечный результат - это что-то вроде двухмерной структуры массива, что некоторые другие, предлагают более способные снаряды.

1
27.01.2020, 20:23

Вот как вы создадите переменную с динамическим именем (версия bash <4.3).

# Dynamically named array
my_variable_name="dyn_arr_names"
eval $my_variable_name=\(\)

# Adding by index to the array eg. dyn_arr_names[0]="bob"
eval $my_variable_name[0]="bob"

# Adding by pushing onto the array eg. dyn_arr_names+=(robert)
eval $my_variable_name+=\(robert\)

# Print value stored at index indirect
echo ${!my_variable_name[0]}

# Print value stored at index
eval echo \${$my_variable_name[0]}

# Get item count
eval echo \${#$my_variable_name[@]}

Ниже представлена ​​группа функций, которые можно использовать для управления массивами с динамическими именами (версия bash <4.3).

# Dynamically create an array by name
function arr() {
    [[ ! "$1" =~ ^[a-zA-Z_]+[a-zA-Z0-9_]*$ ]] && { echo "Invalid bash variable" 1>&2 ; return 1 ; }
     # The following line can be replaced with 'declare -ag $1=\(\)'
     # Note: For some reason when using 'declare -ag $1' without the parentheses will make 'declare -p' fail
    eval $1=\(\)
}

# Insert incrementing by incrementing index eg. array+=(data)
function arr_insert() { 
    [[ ! "$1" =~ ^[a-zA-Z_]+[a-zA-Z0-9_]*$ ]] && { echo "Invalid bash variable" 1>&2 ; return 1 ; }
    declare -p "$1" > /dev/null 2>&1
    [[ $? -eq 1 ]] && { echo "Bash variable [${1}] doesn't exist" 1>&2 ; return 1 ; }
    eval $1[\$\(\(\${#${1}[@]}\)\)]=\$2
}

# Update an index by position
function arr_set() {
    [[ ! "$1" =~ ^[a-zA-Z_]+[a-zA-Z0-9_]*$ ]] && { echo "Invalid bash variable" 1>&2 ; return 1 ; }
    declare -p "$1" > /dev/null 2>&1
    [[ $? -eq 1 ]] && { echo "Bash variable [${1}] doesn't exist" 1>&2 ; return 1 ; }
    eval ${1}[${2}]=\${3}
}

# Get the array content ${array[@]}
function arr_get() {
    [[ ! "$1" =~ ^[a-zA-Z_]+[a-zA-Z0-9_]*$ ]] && { echo "Invalid bash variable" 1>&2 ; return 1 ; }
    declare -p "$1" > /dev/null 2>&1
    [[ $? -eq 1 ]] && { echo "Bash variable [${1}] doesn't exist" 1>&2 ; return 1 ; }
    eval echo \${${1}[@]}
}

# Get the value stored at a specific index eg. ${array[0]}  
function arr_at() {
    [[ ! "$1" =~ ^[a-zA-Z_]+[a-zA-Z0-9_]*$ ]] && { echo "Invalid bash variable" 1>&2 ; return 1 ; }
    declare -p "$1" > /dev/null 2>&1
    [[ $? -eq 1 ]] && { echo "Bash variable [${1}] doesn't exist" 1>&2 ; return 1 ; }
    [[ ! "$2" =~ ^(0|[-]?[1-9]+[0-9]*)$ ]] && { echo "Array index must be a number" 1>&2 ; return 1 ; }
    local v=$1
    local i=$2
    local max=$(eval echo \${\#${1}[@]})
    # Array has items and index is in range
    if [[ $max -gt 0 && $i -ge 0 && $i -lt $max ]]
    then 
        eval echo \${$v[$i]}
    fi
}

# Get the value stored at a specific index eg. ${array[0]}  
function arr_count() {
    [[ ! "$1" =~ ^[a-zA-Z_]+[a-zA-Z0-9_]*$ ]] && { echo "Invalid bash variable " 1>&2 ; return 1 ; }
    declare -p "$1" > /dev/null 2>&1
    [[ $? -eq 1 ]] && { echo "Bash variable [${1}] doesn't exist" 1>&2 ; return 1 ; }
    local v=${1}
    eval echo \${\#${1}[@]}
}



array_names=(bob jane dick)

for name in "${array_names[@]}"
do
    arr dyn_$name
done

echo "Arrays Created"
declare -a | grep "a dyn_"

# Insert three items per array
for name in "${array_names[@]}"
do
    echo "Inserting dyn_$name abc"
    arr_insert dyn_$name "abc"
    echo "Inserting dyn_$name def"
    arr_insert dyn_$name "def"
    echo "Inserting dyn_$name ghi"
    arr_insert dyn_$name "ghi"
done

for name in "${array_names[@]}"
do
    echo "Setting dyn_$name[0]=first"
    arr_set dyn_$name 0 "first"
    echo "Setting dyn_$name[2]=third"
    arr_set dyn_$name 2 "third"
done 

declare -a | grep "a dyn_"

for name in "${array_names[@]}"
do
    arr_get dyn_$name
done


for name in "${array_names[@]}"
do
    echo "Dumping dyn_$name by index"
    # Print by index
    for (( i=0 ; i < $(arr_count dyn_$name) ; i++ ))
    do
        echo "dyn_$name[$i]: $(arr_at dyn_$name $i)"

    done
done

for name in "${array_names[@]}"
do
    echo "Dumping dyn_$name"
    for n in $(arr_get dyn_$name)
    do
        echo $n
    done
done

Ниже представлена ​​группа функций, которые можно использовать для управления массивами с динамическими именами (версия bash> = 4.3).

# Dynamically create an array by name
function arr() {
    [[ ! "$1" =~ ^[a-zA-Z_]+[a-zA-Z0-9_]*$ ]] && { echo "Invalid bash variable" 1>&2 ; return 1 ; }
    declare -g -a $1=\(\)   
}

# Insert incrementing by incrementing index eg. array+=(data)
function arr_insert() { 
    [[ ! "$1" =~ ^[a-zA-Z_]+[a-zA-Z0-9_]*$ ]] && { echo "Invalid bash variable" 1>&2 ; return 1 ; }
    declare -p "$1" > /dev/null 2>&1
    [[ $? -eq 1 ]] && { echo "Bash variable [${1}] doesn't exist" 1>&2 ; return 1 ; }
    declare -n r=$1
    r[${#r[@]}]=$2
}

# Update an index by position
function arr_set() {
    [[ ! "$1" =~ ^[a-zA-Z_]+[a-zA-Z0-9_]*$ ]] && { echo "Invalid bash variable" 1>&2 ; return 1 ; }
    declare -p "$1" > /dev/null 2>&1
    [[ $? -eq 1 ]] && { echo "Bash variable [${1}] doesn't exist" 1>&2 ; return 1 ; }
    declare -n r=$1 
    r[$2]=$3
}

# Get the array content ${array[@]}
function arr_get() {
    [[ ! "$1" =~ ^[a-zA-Z_]+[a-zA-Z0-9_]*$ ]] && { echo "Invalid bash variable" 1>&2 ; return 1 ; }
    declare -p "$1" > /dev/null 2>&1
    [[ $? -eq 1 ]] && { echo "Bash variable [${1}] doesn't exist" 1>&2 ; return 1 ; }
    declare -n r=$1 
    echo ${r[@]}
}

# Get the value stored at a specific index eg. ${array[0]}  
function arr_at() {
    [[ ! "$1" =~ ^[a-zA-Z_]+[a-zA-Z0-9_]*$ ]] && { echo "Invalid bash variable" 1>&2 ; return 1 ; }
    declare -p "$1" > /dev/null 2>&1
    [[ $? -eq 1 ]] && { echo "Bash variable [${1}] doesn't exist" 1>&2 ; return 1 ; }
    [[ ! "$2" =~ ^(0|[-]?[1-9]+[0-9]*)$ ]] && { echo "Array index must be a number" 1>&2 ; return 1 ; }
    declare -n r=$1 
    local max=${#r[@]}
    # Array has items and index is in range
    if [[ $max -gt 0 && $i -ge 0 && $i -lt $max ]]
    then 
        echo ${r[$2]}
    fi
}

# Get the value stored at a specific index eg. ${array[0]}  
function arr_count() {
    [[ ! "$1" =~ ^[a-zA-Z_]+[a-zA-Z0-9_]*$ ]] && { echo "Invalid bash variable " 1>&2 ; return 1 ; }
    declare -p "$1" > /dev/null 2>&1
    [[ $? -eq 1 ]] && { echo "Bash variable [${1}] doesn't exist" 1>&2 ; return 1 ; }
    declare -n r=$1
    echo ${#r[@]}
}



array_names=(bob jane dick)

for name in "${array_names[@]}"
do
    arr dyn_$name
done

echo "Arrays Created"
declare -a | grep "a dyn_"

# Insert three items per array
for name in "${array_names[@]}"
do
    echo "Inserting dyn_$name abc"
    arr_insert dyn_$name "abc"
    echo "Inserting dyn_$name def"
    arr_insert dyn_$name "def"
    echo "Inserting dyn_$name ghi"
    arr_insert dyn_$name "ghi"
done

for name in "${array_names[@]}"
do
    echo "Setting dyn_$name[0]=first"
    arr_set dyn_$name 0 "first"
    echo "Setting dyn_$name[2]=third"
    arr_set dyn_$name 2 "third"
done 

declare -a | grep 'a dyn_'

for name in "${array_names[@]}"
do
    arr_get dyn_$name
done


for name in "${array_names[@]}"
do
    echo "Dumping dyn_$name by index"
    # Print by index
    for (( i=0 ; i < $(arr_count dyn_$name) ; i++ ))
    do
        echo "dyn_$name[$i]: $(arr_at dyn_$name $i)"

    done
done

for name in "${array_names[@]}"
do
    echo "Dumping dyn_$name"
    for n in $(arr_get dyn_$name)
    do
        echo $n
    done
done

Для получения более подробной информации об этих примерах посетите Getting Bashed by Dynamic Arrays, автор Ludvik Jerabek

0
27.01.2020, 20:23

Теги

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