Wie deklariert man -A MYASSOCIATIVEARRY global?

Wie deklariert man -A MYASSOCIATIVEARRY global?

Ich habe genau dasselbe Problem, wie in diesem SO-Beitrag beschrieben („bash-assoziatives Array-Schlüsselstring mit Doppelpunkt gibt Fehler aus“):https://stackoverflow.com/q/40406187/10639803

Die Lösung besteht darin, zu verwenden declare -A, aber sobald ich dies tue, ist mein assoziatives Array nicht mehr global.

Gibt es eine Möglichkeit,declare -A Undes global haben?

UPDATE: Ich habe declare -gAes wie hier beschrieben versucht:https://stackoverflow.com/a/21151984/10639803aber aus irgendeinem Grund funktioniert es bei mir nicht: Sobald ich die Schleife verlasse, die mein assoziatives Array (Hashmap) füllt, wird das Array aufgehoben.

Hier ist der eigentliche Bash-Code (die Echo-Befehle innerhalb der Schleife dienen zur Überprüfung, ob die Werte tatsächlich extrahiert und zugewiesen werden):

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

Antwort1

Das Problem, das Sie sehen, hat nichts mit der Deklaration der Variablen zu tun. Es liegt daran, dass Sie die Variable in einer Subshell festlegen und erwarten, dass ihre Werte im übergeordneten Element verfügbar sind.

Sie können diesen Effekt hier sehen. Dabei wird die gleiche Struktur wie in Ihrem Code verwendet, jedoch ein viel einfacheres Beispiel:

a=""
echo find | while read item; do a="$item"; done
echo "a=$a"

Glücklicherweise bashgibt es bei Verwendung eine schnelle Lösung, indem man den Code in einer anderen Form umschreibt:

a=""
while read item; do a="$item"; done < <( echo find )
echo "a=$a"

Verwenden Sie in echtem Code, while IFS= read -r itemum sicherzustellen, dass itemunverarbeitete Eingaben empfangen werden. Ich habe die Schutzmaßnahmen aus Gründen der Übersichtlichkeit in den Beispielen weggelassen.


In den Kommentaren zu dieser Antwort haben Sie um eine überarbeitete Version Ihres Codes gebeten. Ich kann ihn nicht testen, weshalb ich zunächst gezögert habe, ihn hier zu veröffentlichen, aber er sollte so aussehen:

#!/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

verwandte Informationen