Cree una matriz asociativa a partir de la salida de dos comandos

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 como a=("$x") (donde $x tiene que comenzar con [...]=) además de la sintaxis a=([$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

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *