Estoy tratando de crear directorios de usuario basados en un archivo passwd importado y estoy tratando de cargar los datos en una matriz asociativa: matriz [nombre de usuario] = directorio. Puedo cargar los campos en matrices separadas pero no puedo obtener las asociaciones correctas, ya que cada campo se asocia con todos los directorios.
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
Comentarios
- Si alguna de las respuestas existentes resuelve su problema, considere aceptarlo a través de la marca de verificación. ¡Gracias!
Responder
Podrías leer todo con bash directamente, indicando read para dividir en dos puntos :
declare -A userarray while IFS=: read -r username password uid gid gecos home shell; do userarray[$username]=$home done < /usrmkr/in.out
Responder
eval declare -A USERARRAY=( $(awk -F: "{ printf "[\"%s\"]=\"%s\"\n", $1, $6}" /usrmkr/in.out) )
La secuencia de comandos awk
genera una salida en el formato [key]=val
requerido cuando se configuran varios elementos de una matriz asociativa bash, y entre comillas dobles tanto la clave como el valor (["key"]="value"
) en caso de que haya espacios, pestañas, etc.en las claves o los valores .
He utilizado \n
como separador para facilitar el proceso en caso de que desee postprocesar el awk
salida con alguna otra herramienta (aunque awk
puede hacer la mayoría de las cosas que podría querer hacer con otras herramientas, de todos modos).
Sustitución de comandos debería ser suficiente por sí solo … .pero debido a lo que es, en mi opinión, un error en bash
, si el primer carácter que no es un espacio en blanco dentro de la ( ... )
definición de matriz no es » ta [
, solo produce el mensaje de error must use subscript when assigning associative array
.
p. ej. los dos intentos siguientes para configurar USERARRAY fallarán:
$ 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 solución es para usar eval
al declarar la matriz hash, como en el ejemplo de código en la parte superior de mi respuesta. O
eval declare -A USERARRY=( $UA )
Comentarios
- 1. esto usa
eval
– por supuesto, existe ' s un riesgo de inyección de comandos. Sin embargo, ' no creo que sea ' un problema en este caso, porque mi respuesta está destinada a usarse con el OP ' s específico & presumiblemente examinado / conocido como un archivo de entrada en buen estado. 2. " olvidé citar las expansiones " – ¿eh? ¿Qué? No ' no veo ningún problema de comillas; el código awk cita explícitamente tanto las claves como los valores de la matriz. 3. Por cierto, casi 2 años después, bash v4.4.19 (1) -la versión todavía no ' no le permite usar directamente un cmd-subst o incluso una var en una declaración hash:declare -A array=( $(...) )
falla con el mismo error, por lo que aún se requiere eval - @St é phaneChazelas Si hay ' un problema de citación, explique cómo y por qué, preferiblemente con un ejemplo del mundo real utilizando una entrada de estilo válida / etc / passwd, según sea relevante para esta pregunta y respuesta, no solo un " genérico y obvio, si ingresas datos basura, ' obtendrás resultados impredecibles y potencialmente peligrosos ".
- Usted ' tiene un punto de que normalmente no sería un problema para el
/etc/passwd
datos. Permítanme reformularlo: ⚠ aunque debería estar bien para datos típicos/etc/passwd
, ese enfoque no debería usarse para datos arbitrarios ya que constituiría una vulnerabilidad de inyección de comandos. Específicamente, se supone que los datos no ' no contienen,`
,"
, barra invertida,$
,*
,?
,[
, tabulador de espacio o caracteres NUL. - Acerca del problema de las citas, consulte, por ejemplo, Implicaciones de seguridad de olvidar citar una variable en shells bash / POSIX y las preguntas vinculadas allí para ver qué significa dejar expansiones sin comillas.
- Tenga en cuenta que las versiones anteriores de bash tenían un error donde ' a = (" $ x ") `no podría crear una matriz con un elemento que sea el contenido de
$x
cuando$x
era algo así como[123]=qwe
(eso era antes de que bash soportara matrices asociativas).Este ' s true bash podría haber elegido permitir que las matrices asociativas se declaren comoa=("$x")
(donde$x
tiene que comenzar con[...]=
) además de la sintaxisa=([$k]=$v)
, pero entonces, habría tenido que definir una forma de especificar claves que contienen] caracteres. En cualquier caso, no lo llamaría un error, sino una decisión de diseño (aquí hecha por ksh de donde bash copió su sintaxis).
Respuesta
En lugar de fusionar dos listas, podemos construir la matriz en un solo ciclo (y una sola llamada a awk
por si acaso) devolviendo una lista de usuario: entradas de directorio y luego dividirlo con expansiones de variables:
#!/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
Respuesta
zsh
tiene una forma más útil, más habitual (similar a tcl
o perl
) forma de declarar matrices asociativas como un todo: array=(key1 value1 key2 value2...)
typeset -A userarray IFS=$":\n\n" userarray=($(cut -d : -f 1,6 < /usrmkr/in.out))
Duplicando \n
, como en ksh93
elimina el estado especial de la nueva línea como un carácter de espacio en blanco IFS . Sin él, foo:\nbar:x
se dividiría en «foo», «bar», «x» en lugar de «foo», «», «bar», «x».
Con , la sintaxis es la misma incómoda que en ksh93
: array=([key1]=value1 [key2]=value2)
, por lo que no es fácil obtener el resultado de un comando en una matriz asociativa que no sea mediante el uso de un bucle que realice una asignación de un solo elemento a la vez, como han mostrado otros.
Tenga en cuenta que bash
matrices asociativas ( a diferencia de ksh93
o zsh
) tienen una limitación en el sentido de que la clave no puede ser la cadena vacía (no es un problema aquí). Otra limitación, esta vez compartida con ksh93
es que ni la clave ni los valores pueden contener el byte NUL (tampoco es un problema aquí).
(el soporte de matrices asociativas era en ksh93 desde el principio (1993), agregado a zsh
en 1998 (3.1.5-pws-3) y bash
en 2009 ( 4.0))
Comentarios
- ¿Por qué pusiste ' \ n ' dos veces en IFS?
- @rubystallion ver editar