Snažím se vytvářet uživatelské adresáře na základě importovaného souboru passwd a snažím se načíst data do asociativní pole: pole [uživatelské jméno] = adresář. Mohu načíst pole do samostatných polí, ale nemohu získat správná přidružení, protože každé pole je spojeno se všemi adresáři.
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
Komentáře
- Pokud některá z existujících odpovědí vyřeší váš problém, zvažte přijetí prostřednictvím zaškrtnutí. Děkuji!
Odpověď
Celou věc jste mohli přečíst přímo s bash a přečíst tak, aby se rozdělila na dvojtečky :
declare -A userarray while IFS=: read -r username password uid gid gecos home shell; do userarray[$username]=$home done < /usrmkr/in.out
Odpověď
eval declare -A USERARRAY=( $(awk -F: "{ printf "[\"%s\"]=\"%s\"\n", $1, $6}" /usrmkr/in.out) )
Skript awk
produkuje výstup ve formátu [key]=val
je vyžadováno při nastavování více prvků asociativního pole bash a uvozovky uvozují klíč i hodnotu (["key"]="value"
) v případě, že v klíčích nebo hodnotách jsou mezery, karty atd. .
Použil jsem \n
jako oddělovač, abych to usnadnil pro případ, že byste awk
výstup s jiným nástrojem (i když awk
může dělat většinu věcí, které byste chtěli dělat s jinými nástroji).
Substituce příkazů by mělo stačit samo o sobě .. .ale kvůli tomu, co je, IMO, chyba v bash
, pokud první ne-bílý znak uvnitř ( ... )
definice pole není “ ta [
, pouze vytvoří chybovou zprávu must use subscript when assigning associative array
.
např. oba následující pokusy o nastavení USERARRAY selžou:
$ 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
Řešení je použít eval
při deklaraci hashovaného pole, jako v příkladu kódu v horní části mé odpovědi. Nebo
eval declare -A USERARRY=( $UA )
Komentáře
- 1. toto používá
eval
– samozřejmě existuje ' riziko vložení příkazu. V tomto případě si však ' nemyslím ' problém, protože moje odpověď je určena pro použití s OP ' s konkrétním & pravděpodobně prověřeným / známým dobrým vstupním souborem. 2. " zapomněl jsem uvést rozšíření " – hm? co? Nevidím ' žádný problém s citací – awk kód explicitně cituje oba klíče a hodnoty pro pole. 3. BTW, téměř o 2 roky později, bash v4.4.19 (1) – vydání stále vám ' neumožňuje přímo použít cmd-subst nebo dokonce var v deklaraci hash:declare -A array=( $(...) )
selže se stejnou chybou, takže je stále vyžadováno eval - @St é phaneChazelas Pokud existuje ' problém s citací, pak prosím vysvětlete, jak a proč – nejlépe s příkladem reálného světa s použitím platného vstupu ve stylu / etc / passwd, jak je relevantní pro tuto otázku a odpověď, nejen obecný a zjevný " pokud vkládáte data o odpadcích, získáte ' nepředvídatelné a potenciálně nebezpečné výsledky ".
- Dostali jste ' bod, že pro typické
/etc/passwd
data. Dovolte mi to tedy přeformulovat: ⚠ i když by to mělo být v pořádku pro typická/etc/passwd
data, tento přístup by neměl být použit pro libovolná data, protože by představoval zranitelnost při vkládání příkazů. Konkrétně předpokládá, že data neobsahují ' t,`
,"
, zpětné lomítko,$
,*
,?
,[
, mezera nebo znaky NUL. - O problému s citováním viz například Bezpečnostní důsledky zapomenutí citovat proměnnou v skořápkách bash / POSIX a související otázky, abychom zjistili, co to znamená ponechat expanze necitované.
- Všimněte si, že starší verze bash měly chybu, kde ' a = (" $ x ") `selže při vytváření pole s jedním prvkem, který je obsahem
$x
když$x
bylo něco jako[123]=qwe
(to bylo předtím, než bash podporovala asociativní pole).To ' s true bash se mohlo rozhodnout povolit deklaraci asociativních polí jakoa=("$x")
(kde$x
musí začínat[...]=
) kromě syntaxea=([$k]=$v)
, ale pak by musel definovat způsob, jak specifikovat klíče, které obsahují] znaky. V každém případě bych to nenazval chybou, ale designovým rozhodnutím (zde provedeno ksh, odkud bash zkopíroval svou syntaxi).
Odpovědět
Spíše než slučovat dva seznamy, můžeme sestavit pole v jedné smyčce (a pro dobrou míru jediné volání awk
) vrácením seznamu of user: dir entries then splitting that up with variable expansions:
#!/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
Answer
zsh
má užitečnější, obvyklejší (podobné jako tcl
nebo perl
) způsob deklarace asociativních polí jako celku: array=(key1 value1 key2 value2...)
typeset -A userarray IFS=$":\n\n" userarray=($(cut -d : -f 1,6 < /usrmkr/in.out))
Zdvojnásobení \n
podobně jako v ksh93
odstraní speciální stav nového řádku jako IFS-bílý znak . Bez něj foo:\nbar:x
bude rozdělen na „foo“, „bar“, „x“ namísto „foo“, „“, „bar“, „x“.
S , syntaxe je stejná trapná jako v ksh93
: array=([key1]=value1 [key2]=value2)
, takže nemůžete snadno získat výstup příkazu do asociativního pole jiným způsobem než pomocí smyčky provádějící přiřazení jednoho prvku najednou, jak ukázaly ostatní.
Všimněte si, že bash
asociativní pole ( na rozdíl od ksh93
nebo zsh
) mají omezení v tom, že klíčem nemůže být prázdný řetězec (zde nejde o problém). Dalším omezením, které tentokrát sdílí ksh93
, je to, že klíč ani hodnoty nemohou obsahovat bajt NUL (zde také nejde o problém).
(podpora asociativních polí byla v ksh93 od začátku (1993), přidáno do zsh
v roce 1998 (3.1.5-pws-3) a bash
v roce 2009 ( 4.0))
Komentáře
- Proč jste vložili ' \ n ' dvakrát do IFS?
- @rubystallion zobrazit úpravy