У меня точно такая же проблема, как описано в этом сообщении SO («строка ключа ассоциативного массива bash с двоеточием выдает ошибку»):https://stackoverflow.com/q/40406187/10639803
Решение состоит в использовании , declare -A
но как только я это сделаю, мой ассоциативный массив перестанет быть глобальным.
Есть ли способdeclare -A
ииметь глобальный характер?
ОБНОВЛЕНИЕ: Я попробовал declare -gA
, как описано здесь:https://stackoverflow.com/a/21151984/10639803но у меня это не работает по какой-то причине: как только я выхожу из цикла, который заполняет мой ассоциативный массив (хэш-карту), массив становится неустановленным.
Вот реальный код bash (команды echo внутри цикла нужны для проверки того, что значения действительно извлекаются и назначаются):
declare -gA HOSTS_START_MAP
find "$TEMP" -type f -name "debug.log*" -exec grep -F "STARTING HOST " {} \; |
while IFS= read -r HOST_START_LINE; do
if [[ $HOST_START_LINE =~ (.*)(DEBUG)(.*)(STARTING HOST)([ 0-9]*)(.*)(CALCULATION) ]]
then
HOST_START_TIME=$(echo "${BASH_REMATCH[1]}" | xargs)
HOST_NAME=$(echo "${BASH_REMATCH[6]}" | xargs)
# echo ">$HOST_NAME< ... >$HOST_START_TIME<"
HOSTS_START_MAP[$HOST_NAME]=$HOST_START_TIME
# echo $HOST_NAME --- ${HOSTS_START_MAP[$HOST_NAME]}
fi
done
echo ${#HOSTS_START_MAP[@]}
for MYKEY in "${!HOSTS_START_MAP[@]}"; do echo $MYKEY --- ${HOSTS_START_MAP[@]}; done
решение1
Проблема, которую вы видите, не имеет ничего общего с объявлением переменной. Она возникает из-за того, что вы устанавливаете переменную в подоболочке и ожидаете, что ее значение(я) будут доступны в родительской оболочке.
Вы можете увидеть этот эффект здесь, используя ту же структуру, что и ваш код, но на гораздо более простом примере:
a=""
echo find | while read item; do a="$item"; done
echo "a=$a"
К счастью, при использовании bash
существует быстрое решение, заключающееся в переписывании кода в другой форме:
a=""
while read item; do a="$item"; done < <( echo find )
echo "a=$a"
В реальном коде используйте, while IFS= read -r item
чтобы убедиться, что item
получает необработанный ввод. Я опустил защиту, чтобы, как я надеюсь, сделать примеры более понятными.
В комментариях к этому ответу вы просили переработанную версию вашего кода. Я не могу его протестировать, поэтому я не решился разместить его здесь, но он должен выглядеть так:
#!/bin/bash
#
declare -gA HOSTS_START_MAP
while IFS= read -r HOST_START_LINE; do
if [[ $HOST_START_LINE =~ (.*)(DEBUG)(.*)(STARTING HOST)([ 0-9]*)(.*)(CALCULATION) ]]
then
HOST_START_TIME=$(echo "${BASH_REMATCH[1]}" | xargs)
HOST_NAME=$(echo "${BASH_REMATCH[6]}" | xargs)
# echo ">$HOST_NAME< ... >$HOST_START_TIME<"
HOSTS_START_MAP[$HOST_NAME]=$HOST_START_TIME
# echo $HOST_NAME --- ${HOSTS_START_MAP[$HOST_NAME]}
fi
done < <( find "$TEMP" -type f -name "debug.log*" -exec grep -F "STARTING HOST " {} \; )
echo ${#HOSTS_START_MAP[@]}
for MYKEY in "${!HOSTS_START_MAP[@]}"; do echo $MYKEY --- ${HOSTS_START_MAP[@]}; done