Crea un array associativo dalloutput di due comandi

Sto cercando di creare directory utente in base a un file passwd importato e sto cercando di caricare i dati in un array associativo: array [nome utente] = directory. Posso caricare i campi in array separati ma non riesco a ottenere le associazioni corrette, poiché ogni campo viene associato a tutte le directory.

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 

Commenti

  • Se una qualsiasi delle risposte esistenti risolve il tuo problema, valuta la possibilità di accettarla tramite il segno di spunta. Grazie!

Risposta

Potresti leggere lintera cosa direttamente con bash, dicendo a read di dividere i due punti :

declare -A userarray while IFS=: read -r username password uid gid gecos home shell; do userarray[$username]=$home done < /usrmkr/in.out 

Risposta

 eval declare -A USERARRAY=( $(awk -F: "{ printf "[\"%s\"]=\"%s\"\n", $1, $6}" /usrmkr/in.out) )  

Lo script awk produce output nel formato [key]=val richiesto quando si impostano più elementi di un array associativo bash e virgolette doppie sia per la chiave che per il valore (["key"]="value") nel caso in cui siano presenti spazi, tabulazioni ecc. nelle chiavi o nei valori .

Ho utilizzato \n come separatore per semplificare la post-elaborazione del awk output con qualche altro strumento (sebbene awk possa fare la maggior parte delle cose che potresti voler fare con altri strumenti, comunque).

Sostituzione dei comandi dovrebbe essere sufficiente da solo .. .ma a causa di quello che è, IMO, un bug in bash, se il primo carattere diverso da spazi allinterno della ( ... ) definizione di array non è ” ta [, produce solo il messaggio di errore must use subscript when assigning associative array.

ad es. Entrambi i seguenti tentativi di impostare USERARRAY falliranno:

 $ 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  

La soluzione è utilizzare eval quando si dichiara larray con hash, come nellesempio di codice allinizio della mia risposta. Oppure

eval declare -A USERARRY=( $UA ) 

Commenti

  • 1. questo utilizza eval – ovviamente ' è a rischio di iniezione di comandi. Tuttavia, ' non credo che ' sia un problema in questo caso, perché la mia risposta è intesa per luso con lOP ' s specifico & file di input presumibilmente controllato / noto. 2. " dimenticato di citare le espansioni " – eh? che cosa? Non ' non vedo alcun problema di quotazione: il codice awk cita esplicitamente sia le chiavi che i val per larray. 3. A proposito, quasi 2 anni dopo, bash v4.4.19 (1) -release ancora non ' ti consente di utilizzare direttamente un cmd-subst o addirittura una variabile in una dichiarazione hash: declare -A array=( $(...) ) non riesce con lo stesso errore, quindi eval è ancora obbligatorio
  • @St é phaneChazelas Se ' un problema di citazione, spiega come e perché, preferibilmente con un esempio reale utilizzando un input valido in stile / etc / passwd, in quanto pertinente a questa domanda e risposta, non solo un generico e ovvio " se inserisci dati inutili, ' otterrai risultati imprevedibili e potenzialmente pericolosi ".
  • ' hai capito che in genere non sarebbe un problema per il tipico /etc/passwd dati. Quindi permettimi di riformularlo: ⚠ mentre dovrebbe essere OK per i tipici dati /etc/passwd, quellapproccio non dovrebbe essere usato per dati arbitrari in quanto costituirebbe una vulnerabilità di iniezione di comando. In particolare, si presume che i dati non ' contengano, `, ", barra rovesciata, $, *, ?, [, tabulazione spazio o caratteri NUL.
  • Riguardo al problema delle virgolette, vedere ad esempio Implicazioni sulla sicurezza del dimenticare di citare una variabile nelle shell bash / POSIX e le domande collegate lì per vedere cosa significa lasciare le espansioni non quotate.
  • Nota che le versioni precedenti di bash avevano un bug in cui ' a = (" $ x ") “non riuscirebbe a creare un array con un elemento che è il contenuto di $x quando $x era qualcosa come [123]=qwe (che era prima degli array associativi supportati da bash).La ' vera bash avrebbe potuto scegliere di consentire la dichiarazione di array associativi come a=("$x") (dove $x deve iniziare con [...]=) oltre alla sintassi a=([$k]=$v) ma poi avrebbe dovuto definire un modo per specificare chiavi che contengono] caratteri. In ogni caso, non lo definirei un bug ma una decisione progettuale (qui presa da ksh dove bash ha copiato la sua sintassi).

Risposta

Invece di unire due elenchi, possiamo costruire larray in un unico ciclo (e una singola chiamata a awk per buona misura) restituendo un elenco di voci user: dir, quindi suddividendolo con espansioni variabili:

#!/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 ha un più utile, più usuale (simile a tcl o perl) modo per dichiarare gli array associativi nel loro insieme: array=(key1 value1 key2 value2...)

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

Raddoppio \n, come in ksh93 rimuove lo stato speciale di newline “come carattere IFS-spazio . Senza di esso, foo:\nbar:x verrebbe diviso in “foo”, “bar”, “x” invece di “foo”, “”, “bar”, “x”.

Con , la sintassi è la stessa scomoda di ksh93: array=([key1]=value1 [key2]=value2), quindi non puoi ottenere facilmente loutput di un comando in un array associativo diverso dalluso di un ciclo che esegue lassegnazione di un singolo elemento alla volta come altri hanno mostrato.

Nota che bash array associativi ( contrariamente a ksh93 o zsh) hanno una limitazione in quanto la chiave non può essere una stringa vuota (non è un problema qui). Unaltra limitazione, questa volta condivisa con ksh93, è che né la chiave né i valori possono contenere il byte NUL (anche questo non è un problema).

(il supporto degli array associativi era in ksh93 dallinizio (1993), aggiunto a zsh nel 1998 (3.1.5-pws-3) e bash nel 2009 ( 4.0))

Commenti

  • Perché hai inserito ' \ n ' due volte nellIFS?
  • @rubystallion vedi modifica

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *