Skapa en associerande matris från utdata från två kommandon

Jag försöker skapa användarkataloger baserat på en importerad passwd-fil och försöker ladda in data i en associativ matris: array [username] = katalog. Jag kan ladda fälten i separata matriser men jag kan inte få associationerna korrekta, eftersom varje fält blir associerat med alla kataloger.

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

  • Om något av de befintliga svaren löser ditt problem, överväg att acceptera det via bocken. Tack!

Svar

Du kan läsa hela saken med bash direkt och berätta att läsa att dela 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 ger output i [key]=val -formatet krävs vid inställning av flera element i en bash-associerande matris och dubbla citat både nyckeln och värdet (["key"]="value") om det finns mellanslag, flikar etc i antingen tangenterna eller värdena .

Jag har använt \n som separator för att göra det enkelt om du vill efterbearbeta awk utdata med något annat verktyg (även om awk kan göra det mesta du kanske vill göra med andra verktyg, ändå).

Kommandosubstitution borde vara tillräckligt av sig själv .. .men på grund av vad som är, IMO, ett fel i bash, om det första icke-blankstegstecknet i ( ... ) -definitionen inte är ta [, det ger bara felmeddelandet must use subscript when assigning associative array.

t.ex. båda följande försök att ställa in USERARRAY misslyckas:

 $ 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 är att använda eval när deklarerar den hashade arrayen, som i kodexemplet högst upp i mitt svar. Eller

eval declare -A USERARRY=( $UA ) 

Kommentarer

  • 1. detta använder eval – naturligtvis finns det ' risk för kommandoinjektion. Jag tror inte ' att det ' är ett problem i det här fallet, eftersom mitt svar är avsett för användning med OP ' s specifika & antagligen kontrollerade / kända bra inmatningsfiler. 2. " glömde att citera utvidgningarna " – va? Vad? Jag ser ' inget citatproblem – awk-koden citerar uttryckligen både nycklar och vals för arrayen. 3. BTW, nästan 2 år senare, låter bash v4.4.19 (1) -release still inte ' du inte kan använda en cmd-subst direkt eller till och med a var i en hashdeklaration: declare -A array=( $(...) ) misslyckas med samma fel, så eval krävs fortfarande
  • @St é phaneChazelas Om det ' är ett citeringsproblem, förklara hur och varför – helst med ett verkligt exempel med giltig / etc / passwd-stilinmatning, vilket är relevant för denna fråga och svar, inte bara en generisk och uppenbar " om du matar in skräpdata får du ' oförutsägbara och potentiellt farliga resultat ".
  • Du ' har fått en poäng att det vanligtvis inte skulle vara ett problem för typiska /etc/passwd data. Så låt mig omformulera det: ⚠ även om det borde vara OK för typiska /etc/passwd -data, bör det tillvägagångssättet inte användas för godtyckliga data eftersom det skulle utgöra en sårbarhet vid kommandot. Specifikt antar den att data inte ' t innehåller, `, ", backslash, $, *, ?, [, mellanslag eller NUL-tecken.
  • Om citatproblemet, se till exempel Säkerhetsimplikationer av att glömma att citera en variabel i bash / POSIX-skal och frågorna som länkas där för att se vad det innebär att lämna utvidgningarna ociterade.
  • Observera att äldre versioner av bash hade ett fel där ' a = (" $ x ") `misslyckades med att skapa en matris med ett element som innehållet i $x när $x var något som [123]=qwe (det var före bash-stödda associerade matriser).Det ' s sanna bash kunde ha valt att tillåta associerande matriser att deklareras som a=("$x") (där $x måste börja med [...]=) utöver a=([$k]=$v) syntax men då skulle det ha behövt definiera ett sätt att specificera tangenter som innehåller] tecken. I vilket fall som helst skulle jag inte kalla det en bugg utan ett designbeslut (här gjord av ksh där bash kopierade sin syntax från).

Svar

I stället för att slå samman två listor kan vi bygga arrayen i en enda slinga (och ett enda samtal till awk för gott mått) genom att returnera en lista av användare: dir-poster och sedan dela upp det med variabla utvidgningar:

#!/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 användbar, vanligare (liknar tcl eller perl) sätt att förklara associerande matriser som en helhet: array=(key1 value1 key2 value2...)

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

Fördubbling \n, som i ksh93 tar bort newline ”s specialstatus som ett IFS-mellanslagstecken . Utan det foo:\nbar:x skulle delas upp i ”foo”, ”bar”, ”x” istället för ”foo”, ””, ”bar”, ”x”.

Med , syntaxen är samma besvärliga som i ksh93: array=([key1]=value1 [key2]=value2), så du kan inte enkelt få utdata av ett kommando till en associerande array annan än genom att använda en loop som gör en enskild elementtilldelning åt gången som andra har visat.

Observera att bash associerande matriser ( i motsats till ksh93 eller zsh) har en begränsning genom att nyckeln inte kan vara den tomma strängen (inte ett problem här). En annan begränsning, den här gången delad med ksh93 är att varken nyckel eller värden kan innehålla NUL-byten (inte heller ett problem här).

(stöd för associerande arrays var i ksh93 från början (1993), läggs till zsh 1998 (3.1.5-pws-3) och bash 2009 ( 4.0))

Kommentarer

  • Varför satte du ' \ n ' två gånger till IFS?
  • @rubystallion se redigera

Lämna ett svar

Din e-postadress kommer inte publiceras. Obligatoriska fält är märkta *