Ich versuche, Benutzerverzeichnisse basierend auf einer importierten passwd-Datei zu erstellen und die Daten in zu laden ein assoziatives Array: array [Benutzername] = Verzeichnis. Ich kann die Felder in separate Arrays laden, aber die Zuordnungen können nicht korrekt sein, da jedes Feld allen Verzeichnissen zugeordnet wird.
USERLIST=$(cat /usrmkr/in.out | awk -F ":" "{print $1}") DIRLIST=$(cat /usrmkr/in.out | awk -F ":" "{print $6}") declare -A USERARRAY func_StoreData() { USERARRAY[$1]="$2" return $? } for ((u=0;u<${USERLIST[@]};u++)); do func_StoreData ${USERLIST[$u]} ${DIRLIST[$u]} done for i in ${!USERARRAY[@]}; do echo "making directory for $i in ${USERARRAY[$i]}" #Do stuff done
Kommentare
- Wenn eine der vorhandenen Antworten Ihr Problem löst, ziehen Sie bitte in Betracht, sie über zu akzeptieren das Häkchen. Vielen Dank!
Antwort
Sie können das Ganze direkt mit bash lesen und lesen, dass das Lesen auf Doppelpunkte aufgeteilt werden soll :
declare -A userarray while IFS=: read -r username password uid gid gecos home shell; do userarray[$username]=$home done < /usrmkr/in.out
Antwort
eval declare -A USERARRAY=( $(awk -F: "{ printf "[\"%s\"]=\"%s\"\n", $1, $6}" /usrmkr/in.out) )
Das Skript awk
erzeugt eine Ausgabe im Format [key]=val
Erforderlich, wenn mehrere Elemente eines assoziativen Bash-Arrays festgelegt werden und sowohl der Schlüssel als auch der Wert (["key"]="value"
) in doppelte Anführungszeichen gesetzt werden, falls in den Schlüsseln oder den Werten Leerzeichen, Tabulatoren usw. vorhanden sind
Ich habe \n
als Trennzeichen verwendet, um es einfacher zu machen, falls Sie die awk
Ausgabe mit einem anderen Tool (obwohl awk
die meisten Dinge tun kann, die Sie möglicherweise mit anderen Tools tun möchten).
Befehlsersetzung sollte alleine ausreichen. Aber aufgrund dessen, was IMO ist, ist ein Fehler in bash
, wenn das erste Nicht-Leerzeichen in der ( ... )
Array-Definition nicht „ist. ta [
erzeugt nur die Fehlermeldung must use subscript when assigning associative array
.
z Beide der folgenden Versuche, USERARRAY festzulegen, schlagen fehl:
$ bash --version | head -1 GNU bash, version 4.3.46(1)-release (x86_64-pc-linux-gnu) $ declare -A USERARRAY=($(awk -F: "{ printf "[\"%s\"]=\"%s\"\n", $1, $6}" /usrmkr/in.out)) bash: USERARRAY: $(awk -F: "{ printf "[\"%s\"]=\"%s\"\n", $1, $6}" /usrmkr/in.out): must use subscript when assigning associative array $ UA=$(awk -F: "{ printf "[\"%s\"]=\"%s\"\n", $1, $6}" /usrmkr/in.out) $ declare -A USERARRAY=( $UA ) bash: USERARRAY: $UA: must use subscript when assigning associative array
Die Lösung lautet Verwenden Sie eval
, wenn Sie das Hash-Array deklarieren, wie im Codebeispiel oben in meiner Antwort. Oder
eval declare -A USERARRY=( $UA )
Kommentare
- 1. Dies verwendet
eval
– natürlich besteht ' das Risiko einer Befehlsinjektion. Ich glaube nicht, dass ' ' in diesem Fall ein Problem ist, da meine Antwort für die Verwendung mit der OP ' s spezifische & vermutlich überprüfte / bekanntermaßen gute Eingabedatei. 2. " hat vergessen, die Erweiterungen zu zitieren " – nicht wahr? Was? Ich sehe ' kein Anführungsproblem – der awk-Code zitiert explizit sowohl Schlüssel als auch Werte für das Array. 3. Übrigens, fast 2 Jahre später lässt bash v4.4.19 (1) -release noch ' Sie nicht direkt einen cmd-subst oder sogar verwenden Ein var in einer Hash-Deklaration:declare -A array=( $(...) )
schlägt mit demselben Fehler fehl, daher ist eine Auswertung weiterhin erforderlich. - @St é phaneChazelas Wenn ' ein Zitatproblem vorliegt, erläutern Sie bitte, wie und warum – vorzugsweise anhand eines Beispiels aus der Praxis unter Verwendung einer gültigen Eingabe im Stil / etc / passwd, die für diese Frage und Antwort relevant ist. Nicht nur ein generisches und offensichtliches " Wenn Sie Mülldaten eingeben, erhalten Sie ' unvorhersehbare und potenziell gefährliche Ergebnisse ".
- Sie ' haben den Punkt, dass dies für typische
/etc/passwd
Daten. Lassen Sie es mich umformulieren: ⚠ Während es für typische/etc/passwd
-Daten in Ordnung sein sollte, sollte dieser Ansatz nicht für beliebige Daten verwendet werden, da dies eine Sicherheitsanfälligkeit bezüglich Befehlsinjektion darstellen würde. Insbesondere wird davon ausgegangen, dass die Daten ' nicht enthalten,`
,"
, Backslash,$
,*
,?
,[
, Leerzeichen oder NUL-Zeichen. - Informationen zum Anführungszeichenproblem finden Sie beispielsweise unter Sicherheitsaspekte, wenn Sie vergessen, eine Variable in Bash / POSIX-Shells anzugeben und die dort verknüpften Fragen, um zu sehen, was es bedeutet, Erweiterungen nicht in Anführungszeichen zu setzen.
- Beachten Sie, dass ältere Versionen von bash einen Fehler hatten, bei dem ' a = (" $ x ") `würde kein Array erstellen, wobei ein Element der Inhalt von
$x
wenn$x
so etwas wie[123]=qwe
war (das war, bevor Bash assoziative Arrays unterstützte).' könnte sich dafür entschieden haben, assoziative Arrays alsa=("$x")
deklarieren zu können (wobei$x
muss zusätzlich zura=([$k]=$v)
-Syntax mit[...]=
) beginnen, hätte dann aber eine Art der Angabe definieren müssen Schlüssel, die] Zeichen enthalten. Auf jeden Fall würde ich es nicht als Fehler bezeichnen, sondern als Entwurfsentscheidung (hier von ksh getroffen, von wo bash seine Syntax kopiert hat).
Antwort
Anstatt zwei Listen zusammenzuführen, können wir das Array in einer einzigen Schleife erstellen (und einen einzelnen Aufruf von awk
für ein gutes Maß), indem wir eine Liste zurückgeben of user: dir-Einträge teilen diese dann mit variablen Erweiterungen auf:
#!/bin/bash declare -A USERARRAY for u in $(awk -F: "{print $1 ":" $6}" /usrmkr/in.out) do user=${u%:*} dir=${u#*:} USERARRAY[$user]=$dir done
Antwort
zsh
hat eine nützlichere, üblichere (ähnlich wie tcl
oder perl
) Möglichkeit, assoziative Arrays als Ganzes zu deklarieren: array=(key1 value1 key2 value2...)
typeset -A userarray IFS=$":\n\n" userarray=($(cut -d : -f 1,6 < /usrmkr/in.out))
Verdoppeln von \n
, wie in ksh93
entfernt den Sonderstatus von newline als IFS-Whitespace-Zeichen . Ohne dieses Zeichen foo:\nbar:x
würde in „foo“, „bar“, „x“ anstelle von „foo“, „“, „bar“, „x“ aufgeteilt.
Mit ist die Syntax dieselbe umständliche wie in ksh93
: array=([key1]=value1 [key2]=value2)
, sodass Sie die Ausgabe nicht einfach erhalten können eines Befehls in ein anderes assoziatives Array als durch Verwendung einer Schleife, die jeweils eine einzelne Elementzuweisung ausführt, wie andere gezeigt haben.
Beachten Sie, dass bash
assoziative Arrays ( Im Gegensatz zu ksh93
oder zsh
) besteht eine Einschränkung darin, dass der Schlüssel nicht die leere Zeichenfolge sein kann (hier kein Problem). Eine weitere Einschränkung, die diesmal mit ksh93
geteilt wird, besteht darin, dass weder Schlüssel noch Werte das NUL-Byte enthalten können (auch hier kein Problem).
(Unterstützung für assoziative Arrays war in ksh93 von Anfang an (1993), 1998 zu zsh
hinzugefügt (3.1.5-pws-3) und bash
2009 ( 4.0))
Kommentare
- Warum haben Sie ' \ n zweimal in das IFS?
- @rubystallion siehe bearbeiten