Ссылка на переменные массива bash из другого массива

Вот несколько команд для копирования каталогов с информацией о ходе выполнения.


Если есть много маленьких файлов:

cp -av sourcedir targetdir | pv -l -s filecount > logfile

Это сообщит о прогрессе, основанном на количестве копируемых файлов.

Вы можете перенаправить на /dev/null, если вам не нужен logfile.

Используйте следующую команду для получения filecount:

find sourcedir | wc -l

Если есть несколько огромных файлов:

tar c sourcedir | pv -s size | tar x -C targetdir

Это сообщит о прогрессе на основе байтов, которые копируются.

targetdir должен существовать.

Используйте следующую команду для получения size:

du -sh sourcedir

Если вы хотите использовать rsync:

rsync -ai sourcedir/ targetdir/ | pv -l -s filecount > logfile

Получите filecount, как показано выше.

Если вы копируете в одной системе, то rsync -a практически то же самое, что cp -a . Преимущества rsync - при копировании по сети или при обновлении (или сравнении) предыдущей копии.

См. подробнее здесь:

8
06.09.2017, 20:12
3 ответа

Bash 4.3 и более поздние версииподдерживают «ссылки на имена» или namerefs (аналогичная концепция существует в ksh93, но область видимости раздражает different):

#!/bin/bash

array1=('array1string1' 'array1string2')
array2=('array2string1' 'array2string2')

array_names=('array1' 'array2')

for a in "${array_names[@]}"; do
    declare -n arr="$a"

    for b in "${arr[@]}"; do
        echo "$b"
    done
done

Переменная arrявляется ссылкой на имя, которая действует как псевдоним для именованной переменной (в данном примере это переменная с именем $a).

Без ссылок namerefs в более ранних версиях Bash одним из решений было бы создание нового массива, содержащего все элементы из других массивов:

all=( "${array1[@]}" "${array2[@]}" )

... немного похоже на массив array_namesв вопрос, но с содержимым всех массивов, а затем перебрать "${all[@]}".

Также можно использовать eval, но полученный код выглядит поразительно ужасно.

См. ответ glenn jackman для варианта с переменной косвенностью (представленный в его текущей форме с Bash версии 2).

8
27.01.2020, 20:11

У @Kusalananda есть лучший ответ для последних версий bash. Для более ранних версий вы можете использовать косвенную переменную:

for a in ${array_names[@]}; do 
    tmp="${a}[@]"
    for b in "${!tmp}"; do echo "$b"; done     # or: printf "%s\n" "${!tmp}"
done

См. 4-й абзацhttps://www.gnu.org/software/bash/manual/bashref.html#Shell-Parameter-Expansion

3
27.01.2020, 20:11

В качестве вариации сказанного:

#!/bin/bash

array1=('array1 string1' 'array1 string2')
array2=('array2 string1' 'array2 string2')
array_names=('array1' 'array2')

for (( i=0; i<${#array_names[@]}; i++ )); do

    declare -n arr="${array_names[i]}"

    for (( j=0; j<${#arr[@]}; j++ )); do
        echo "${arr[j]}"
    done

done

Доступ к элементам по индексу вместо этого

0
27.01.2020, 20:11

Теги

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