Vytvořte asociativní pole z výstupu dvou příkazů

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í jako a=("$x") (kde $x musí začínat [...]=) kromě syntaxe a=([$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

Napsat komentář

Vaše e-mailová adresa nebude zveřejněna. Vyžadované informace jsou označeny *