Încerc să creez directoare de utilizator pe baza unui fișier passwd importat și încerc să încărc datele în o matrice asociativă: matrice [nume utilizator] = director. Pot încărca câmpurile într-o matrice separată, dar nu pot obține asocierile corecte, deoarece fiecare câmp se asociază cu toate directoarele.
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
Comentarii
- Dacă vreunul dintre răspunsurile existente rezolvă problema dvs., vă rugăm să luați în considerare acceptarea acesteia prin bifa. Vă mulțumim!
Răspundeți
Ați putea citi totul cu bash direct, spunând citirii să se împartă pe două puncte :
declare -A userarray while IFS=: read -r username password uid gid gecos home shell; do userarray[$username]=$home done < /usrmkr/in.out
Răspuns
eval declare -A USERARRAY=( $(awk -F: "{ printf "[\"%s\"]=\"%s\"\n", $1, $6}" /usrmkr/in.out) )
Scriptul awk
produce ieșire în format [key]=val
obligatoriu la setarea mai multor elemente ale unui tablou asociativ bash și ghilimelele atât pentru cheie cât și pentru valoare (["key"]="value"
) în cazul în care există spații, file etc. fie în taste, fie în valori .
Am „folosit div \n
ca separator pentru a ușura situația în cazul în care doriți să prelucrați awk
ieșire cu un alt instrument (deși awk
poate face oricum majoritatea lucrurilor pe care ați putea dori să le faceți cu alte instrumente).
Înlocuirea comenzii ar trebui ca să fie suficient de unul singur .. .dar din cauza a ceea ce este, IMO, un bug în bash
, dacă primul caracter non-spațiu din interiorul ( ... )
definiția matricei nu este ta [
, produce doar mesajul de eroare must use subscript when assigning associative array
.
de ex. ambele încercări următoare de a seta USERARRAY vor eșua:
$ 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
Soluția este să folosesc eval
la declararea matricei hash, ca în exemplul de cod din partea de sus a răspunsului meu. Sau,
eval declare -A USERARRY=( $UA )
Comentarii
- 1. aceasta folosește
eval
– desigur, există ' un risc de injectare a comenzii. ' nu cred că este ' o problemă în acest caz, totuși, deoarece răspunsul meu este destinat utilizării cu OP ' s & fișier de intrare probabil verificat / cunoscut-bun. 2. " a uitat să citez expansiunile " – nu? ce? Nu ' nu văd nicio problemă de citare – codul awk citează în mod explicit atât cheile, cât și valorile pentru matrice. 3. BTW, aproape 2 ani mai târziu, bash v4.4.19 (1) -lansare încă nu ' vă permite să utilizați direct un CMD-subst sau chiar o var într-o declarație hash:declare -A array=( $(...) )
eșuează cu aceeași eroare, așa că este necesară evaluarea - @St é phaneChazelas Dacă există ' o problemă de citare, vă rugăm să explicați cum și de ce – de preferință cu un exemplu din lumea reală folosind un stil valid / etc / passwd, așa cum este relevant pentru această întrebare și răspuns, nu doar un generic și evident " dacă vă hrăniți cu date despre gunoi, ' veți obține rezultate imprevizibile și potențial periculoase ".
- Ai ' ai un punct că de obicei nu ar fi o problemă pentru
/etc/passwd
date. Deci, permiteți-mi să o reformulez: ⚠ în timp ce ar trebui să fie OK pentru datele tipice/etc/passwd
, această abordare nu ar trebui utilizată pentru date arbitrare, deoarece ar constitui o vulnerabilitate de injecție a comenzilor. În mod specific, presupune că datele nu conțin ',`
,"
, bară inversă,$
,*
,?
,[
, fila spațiu sau caractere NUL. - Despre problema de citare, consultați de exemplu Implicațiile de securitate ale uitării de a cita o variabilă în shell-urile bash / POSIX și întrebările legate acolo pentru a vedea ce înseamnă a lăsa extinderi necitate.
- Rețineți că versiunile mai vechi de bash au avut o eroare în care ' a = (" $ x ") `nu va reuși să creeze o matrice cu un singur element fiind conținutul
$x
când$x
era ceva de genul[123]=qwe
(care a fost înainte ca bash să accepte matrice asociative).' adevăratul bash ar fi putut alege să permită declararea matricilor asociative caa=("$x")
(unde$x
trebuie să înceapă cu[...]=
) în plus față de sintaxaa=([$k]=$v)
, dar ar fi trebuit să definească un mod de a specifica chei care conțin] caractere. În orice caz, nu l-aș numi un bug, ci o decizie de proiectare (aici luată de ksh de unde bash și-a copiat sintaxa).
Răspuns
În loc să fuzioneze două liste, putem construi matricea într-o singură buclă (și un singur apel către awk
pentru o măsură bună) returnând o listă de intrări utilizator: dir, apoi împărțind asta cu expansiuni variabile:
#!/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
Răspuns
zsh
are un aspect mai util, mai obișnuit (similar cu tcl
sau perl
) modalitate de a declara matrici asociative ca întreg: array=(key1 value1 key2 value2...)
typeset -A userarray IFS=$":\n\n" userarray=($(cut -d : -f 1,6 < /usrmkr/in.out))
Dublare \n
, ca în ksh93
elimină statutul special al liniei noi ca caracter IFS-spațiu alb . Fără acesta, foo:\nbar:x
ar fi împărțit în „foo”, „bar”, „x” în loc de „foo”, „”, „bar”, „x”.
Cu , sintaxa este aceeași ciudată ca în ksh93
: array=([key1]=value1 [key2]=value2)
, deci nu puteți obține cu ușurință ieșirea a unei comenzi într-un tablou asociativ, altul decât prin utilizarea unei bucle care efectuează un singur element de atribuire la un moment dat, așa cum au arătat alții. spre deosebire de ksh93
sau zsh
) au o limitare prin faptul că cheia nu poate fi șirul gol (nu este o problemă aici). O altă limitare, de această dată împărtășită cu ksh93
este că nici cheia, nici valorile nu pot conține octetul NUL (de asemenea, nu este o problemă aici).
(suportul pentru matricile asociative a fost în ksh93 de la început (1993), adăugat la zsh
în 1998 (3.1.5-pws-3) și bash
în 2009 ( 4.0))
Comentarii
- De ce ați pus ' \ n ' de două ori în IFS?
- @rubystallion vezi modificarea