Opret et associerende array fra output af to kommandoer

Jeg prøver at oprette brugerkataloger baseret på en importeret passwd-fil og prøver at indlæse dataene i et associerende array: array [brugernavn] = bibliotek. Jeg kan indlæse felterne i separate arrays, men jeg kan ikke få tilknytningerne korrekte, da hvert felt bliver tilknyttet alle mapper.

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 et af de eksisterende svar løser dit problem, kan du overveje at acceptere det via afkrydsningsmærket. Tak!

Svar

Du kunne læse det hele med bash direkte og fortælle læs at opdele 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 scriptet producerer output i [key]=val format kræves, når du indstiller flere elementer i et bash-associerende array, og citerer både nøglen og værdien (["key"]="value"), hvis der er mellemrum, faner osv. i enten tasterne eller værdierne .

Jeg har brugt \n som separator for at gøre det let, hvis du vil efterbehandle awk output med et andet værktøj (skønt awk alligevel kan gøre de fleste ting, du måske vil gøre med andre værktøjer).

Kommandosubstitution skal være nok af sig selv .. .men på grund af hvad der er, IMO, en fejl i bash, hvis det første ikke-hvide mellemrumstegn inde i ( ... ) -definitionen ikke er ” ta [, det producerer bare fejlmeddelelsen must use subscript when assigning associative array.

f.eks. begge følgende forsøg på at indstille 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 at bruge eval, når jeg erklærer det hashede array, som i kodeeksemplet øverst i mit svar. Eller

eval declare -A USERARRY=( $UA ) 

Kommentarer

  • 1. dette bruger eval – selvfølgelig er der ' en risiko for kommandoindsprøjtning. Jeg tror ikke ' det ' er et problem i dette tilfælde, fordi mit svar er beregnet til brug sammen med OP ' s specifik & formodentlig kontrolleret / kendt god inputfil. 2. " glemte at citere udvidelserne " – hva? hvad? Jeg ser ' ikke noget citatproblem – awk-koden citerer eksplicit både nøgler og vals til arrayet. 3. BTW, næsten 2 år senere, giver bash v4.4.19 (1) -frigivelse stadig ikke ' dig ikke direkte brug af en cmd-subst eller endda a var i en hash-erklæring: declare -A array=( $(...) ) mislykkes med samme fejl, så eval er stadig påkrævet
  • @St é phaneChazelas Hvis der ' er et citerende problem, så forklar venligst hvordan og hvorfor – helst med et eksempel fra den virkelige verden ved hjælp af gyldig / etc / passwd stil input, som det er relevant for dette spørgsmål og svar ikke bare en generisk og åbenlys " hvis du fodrer med skraldata, får du ' uforudsigelige og potentielt farlige resultater ".
  • Du ' har fået et punkt, at det typisk ikke ville være et problem for typisk /etc/passwd data. Så lad mig omformulere det: ⚠ mens det skal være OK for typiske /etc/passwd data, bør denne tilgang ikke bruges til vilkårlige data, da det ville udgøre en sårbarhed ved kommandoindsprøjtning. Specifikt antager det, at dataene ikke ' t indeholder, `, ", tilbageslag $, *, ?, [, mellemrumstasten eller NUL-tegn.
  • Om citatproblemet, se f.eks. Sikkerhedsimplikationer ved at glemme at citere en variabel i bash / POSIX-skaller og de spørgsmål, der er knyttet dertil for at se, hvad det betyder at lade udvidelser ikke citeres.
  • Bemærk, at ældre versioner af bash havde en fejl, hvor ' a = (" $ x ") `kunne ikke oprette en matrix med et element som indholdet af $x når $x var noget som [123]=qwe (det var før bash-understøttede associerende arrays).Det ' s sande bash kunne have valgt at tillade associerende arrays at blive deklareret som a=("$x") (hvor $x skal starte med [...]=) ud over a=([$k]=$v) syntaksen, men så ville det have været nødvendigt at definere en måde at specificere nøgler, der indeholder] tegn. Under alle omstændigheder vil jeg ikke kalde det en fejl, men en designbeslutning (her taget af ksh, hvor bash kopierede sin syntaks fra).

Svar

I stedet for at flette to lister, kan vi oprette arrayet i en enkelt loop (og et enkelt opkald til awk for godt mål) ved at returnere en liste af bruger: dir-indgange derefter opdele det med variable udvidelser:

#!/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 mere nyttig, mere almindelig (svarer til tcl eller perl) måde at erklære associerende arrays som en helhed på: array=(key1 value1 key2 value2...)

typeset -A userarray IFS=$":\n\n" userarray=($(cut -d : -f 1,6 < /usrmkr/in.out)) 

Fordobling \n, som i ksh93 fjerner den nye linies specielle status som et IFS-hvidt mellemrumstegn . Uden det foo:\nbar:x ville blive opdelt i “foo”, “bar”, “x” i stedet for “foo”, “”, “bar”, “x”.

Med , syntaksen er den samme akavede som i ksh93: array=([key1]=value1 [key2]=value2), så du kan ikke let få output af en kommando i et associerende array andet end ved at bruge en loop, der udfører en enkelt elementtildeling ad gangen, som andre har vist. i modsætning til ksh93 eller zsh) har en begrænsning, fordi nøglen ikke kan være den tomme streng (ikke et problem her). En anden begrænsning, denne gang delt med ksh93 er, at hverken nøgle eller værdier kan indeholde NUL-byten (heller ikke et problem her).

(understøttelse af associerende arrays var i ksh93 fra starten (1993), tilføjet til zsh i 1998 (3.1.5-pws-3) og bash i 2009 ( 4.0))

Kommentarer

  • Hvorfor satte du ' \ n ' to gange i IFS?
  • @rubystallion se redigering

Skriv et svar

Din e-mailadresse vil ikke blive publiceret. Krævede felter er markeret med *