Jeg prøver å lage brukerkataloger basert på en importert passwd-fil, og prøver å laste dataene inn en assosiativ matrise: array [brukernavn] = katalog. Jeg kan laste feltene i separate matriser, men jeg kan ikke få assosiasjonene korrekte, ettersom hvert felt blir assosiert med alle katalogene.
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
Kommentarer
- Hvis noen av de eksisterende svarene løser problemet ditt, kan du vurdere å godta det via haken. Tusen takk!
Svar
Du kan lese hele greia med bash direkte, og fortelle lese å dele på kolon. :
declare -A userarray while IFS=: read -r username password uid gid gecos home shell; do userarray[$username]=$home done < /usrmkr/in.out
Svar
eval declare -A USERARRAY=( $(awk -F: "{ printf "[\"%s\"]=\"%s\"\n", $1, $6}" /usrmkr/in.out) )
awk
-skriptet produserer utdata i [key]=val
-formatet kreves når du setter flere elementer i en bash-assosiativ matrise, og dobbelt siterer både nøkkelen og verdien (["key"]="value"
) i tilfelle det er mellomrom, faner osv. i enten tastene eller verdiene .
Jeg har brukt \n
som skilletegn for å gjøre det enkelt i tilfelle du vil etterbehandle awk
output med et annet verktøy (selv om awk
kan gjøre det meste du kanskje vil gjøre med andre verktøy, uansett).
Kommandosubstitusjon skal være nok av seg selv .. .men på grunn av det som er, IMO, en feil i bash
, hvis det første ikke-hvite mellomromstegnet i ( ... )
-definisjonen ikke er » ta [
, den gir bare feilmeldingen must use subscript when assigning associative array
.
f.eks. begge følgende forsøk på å angi USERARRAY mislykkes:
$ 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
Løsningen er å bruke eval
når jeg erklærer hash-arrayet, som i kodeeksemplet øverst i svaret mitt. Eller
eval declare -A USERARRY=( $UA )
Kommentarer
- 1. dette bruker
eval
– selvfølgelig er det ' en risiko for kommandoinjeksjon. Jeg tror ikke ' det ' er et problem i dette tilfellet, fordi svaret mitt er ment for bruk med OP ' s spesifikk & antagelig kontrollert / kjent god inndatafil. 2. " glemte å sitere utvidelsene " – hva? hva? Jeg ser ikke ' noe siteringsproblem – awk-koden siterer eksplisitt både nøkler og vals for matrisen. 3. BTW, nesten 2 år senere, bash v4.4.19 (1) -utgivelse fortsatt lar deg ikke ' ikke bruke en cmd-subst direkte eller til og med en var i en hash-erklæring:declare -A array=( $(...) )
mislykkes med samme feil, så eval er fortsatt nødvendig - @St é phaneChazelas Hvis det ' et siteringsproblem, vennligst forklar hvordan og hvorfor – helst med et eksempel fra den virkelige verden som bruker gyldig / etc / passwd stilinngang, som er relevant for dette spørsmålet og svaret ikke bare en generisk og åpenbar " hvis du mater inn søppeldata, får du ' uforutsigbare og potensielt farlige resultater ".
- Du ' har fått et poeng om at det vanligvis ikke ville være et problem for typiske
/etc/passwd
data. Så la meg omformulere det: ⚠ mens det skal være OK for typiske/etc/passwd
-data, bør denne tilnærmingen ikke brukes til vilkårlige data, da det vil utgjøre et sårbarhet ved kommandainjeksjon. Spesielt antar den at dataene ikke inneholder ' t,`
,"
, tilbakeslag$
,*
,?
,[
, mellomromstasten eller NUL-tegn. - Om siteringsproblemet, se for eksempel Sikkerhetsimplikasjoner av å glemme å sitere en variabel i bash / POSIX-skall og spørsmålene som er knyttet der for å se hva det vil si å la utvidelser være unoterte.
- Merk at eldre versjoner av bash hadde en feil der ' a = (" $ x ") `mislyktes i å lage en matrise med ett element som innholdet i
$x
når$x
var noe sånt som[123]=qwe
(det var før bash-støttede assosiative matriser).Det ' s sanne bash kunne ha valgt å tillate assosiative matriser å bli erklært soma=("$x")
(der$x
må begynne med[...]=
) i tillegg tila=([$k]=$v)
syntaksen, men da måtte den definere en måte å spesifisere nøkler som inneholder] tegn. I alle fall vil jeg ikke kalle det en feil, men en designbeslutning (her tatt av ksh hvor bash kopierte syntaksen fra).
Svar
I stedet for å slå sammen to lister, kan vi bygge matrisen i en enkelt sløyfe (og et enkelt anrop til awk
for godt mål) ved å returnere en liste av bruker: dir-oppføringer og deretter dele det opp med variable utvidelser:
#!/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
Svar
zsh
har en mer nyttig, mer vanlig (ligner tcl
eller perl
) måte å erklære assosiative matriser som en helhet: array=(key1 value1 key2 value2...)
typeset -A userarray IFS=$":\n\n" userarray=($(cut -d : -f 1,6 < /usrmkr/in.out))
Dobling \n
, som i ksh93
fjerner den nye linjens spesielle status som et IFS-mellomromstegn . Uten det foo:\nbar:x
vil bli delt inn i «foo», «bar», «x» i stedet for «foo», «», «bar», «x».
Med , syntaksen er den samme vanskelig som i ksh93
: array=([key1]=value1 [key2]=value2)
, slik at du ikke enkelt kan få utdata av en kommando i en assosiativ matrise annet enn ved å bruke en sløyfe som utfører en enkelt elementtilordning om gangen som andre har vist.
Merk at bash
assosierende matriser ( i motsetning til ksh93
eller zsh
) har en begrensning ved at nøkkelen ikke kan være den tomme strengen (ikke et problem her). En annen begrensning, denne gangen delt med ksh93
, er at verken nøkkel eller verdier kan inneholde NUL-byten (heller ikke noe problem her).
(støtte for assosiative arrays var i ksh93 fra starten (1993), lagt til zsh
i 1998 (3.1.5-pws-3) og bash
i 2009 ( 4.0))
Kommentarer
- Hvorfor la du ' \ n ' to ganger inn i IFS?
- @rubystallion se rediger