Crie uma matriz associativa a partir da saída de dois comandos

Estou tentando criar diretórios de usuário com base em um arquivo passwd importado e estou tentando carregar os dados em uma matriz associativa: array [nome de usuário] = diretório. Posso carregar os campos em matrizes separadas, mas não consigo obter as associações corretas, pois cada campo é associado a todos os diretórios.

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 

Comentários

  • Se alguma das respostas existentes resolver o seu problema, considere aceitá-la por a marca de seleção. Obrigado!

Resposta

Você poderia ler tudo com bash diretamente, dizendo para ler para dividir em dois pontos :

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

Resposta

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

O awk script produz saída no formato [key]=val obrigatório ao definir vários elementos de uma matriz associativa bash e aspas duplas tanto a chave quanto o valor (["key"]="value") no caso de haver espaços, tabulações etc. nas chaves ou nos valores .

Usei \n como separador para facilitar, caso você queira pós-processar o awk saída com alguma outra ferramenta (embora awk possa fazer a maioria das coisas que você pode querer fazer com outras ferramentas, de qualquer maneira).

Substituição de comando deve ser suficiente por si só .. .mas devido ao que é, IMO, um bug em bash, se o primeiro caractere diferente de espaço em branco dentro da ( ... ) definição de matriz isn ” ta [, apenas produz a mensagem de erro must use subscript when assigning associative array.

por exemplo ambas as tentativas a seguir para definir USERARRAY falharão:

 $ 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  

A solução é para usar eval ao declarar a matriz em hash, como no exemplo de código no início da minha resposta. Ou

eval declare -A USERARRY=( $UA ) 

Comentários

  • 1. isso usa eval – é claro que há ' o risco de injeção de comando. Não ' não acho que ' seja um problema neste caso, porque minha resposta deve ser usada com o OP ' s & arquivo de entrada presumivelmente verificado / em bom estado. 2. " esqueceu de citar as expansões " – hein? que? Eu não ' não vejo nenhum problema de cotação – o código awk explicitamente cita chaves e vals para o array. 3. Aliás, quase 2 anos depois, o bash v4.4.19 (1) -release ainda ' não permite que você use diretamente um cmd-subst ou mesmo uma var em uma declaração hash: declare -A array=( $(...) ) falha com o mesmo erro, então eval ainda é necessário
  • @St é phaneChazelas Se houver ' um problema de cotação, explique como e por quê – de preferência com um exemplo do mundo real usando entrada de estilo / etc / passwd válida, conforme for relevante para esta pergunta e resposta não apenas um " óbvio e genérico, se você inserir dados de lixo, ' obterá resultados imprevisíveis e potencialmente perigosos ".
  • Você ' concluiu que normalmente não seria um problema para um /etc/passwd data. Então, deixe-me reformular: ⚠ embora deva ser OK para dados /etc/passwd típicos, essa abordagem não deve ser usada para dados arbitrários, pois constituiria uma vulnerabilidade de injeção de comando. Especificamente, ele assume que os dados não ' contêm, `, ", barra invertida, $, *, ?, [, tabulação de espaço ou caracteres NUL.
  • Sobre o problema de citação, consulte por exemplo Implicações de segurança de se esquecer de citar uma variável em shells bash / POSIX e as questões vinculadas lá para ver o que significa deixar expansões sem aspas.
  • Observe que as versões mais antigas do bash tinham um bug onde ' a = (" $ x ") `não conseguiria criar uma matriz com um elemento sendo o conteúdo de $x quando $x era algo como [123]=qwe (isso era antes de matrizes associativas suportadas pelo bash).O ' s verdadeiro bash poderia ter escolhido permitir que matrizes associativas fossem declaradas como a=("$x") (onde $x tem que começar com [...]=) além da sintaxe a=([$k]=$v), mas então, teria que definir uma maneira de especificar chaves que contêm] caracteres. Em qualquer caso, eu não o chamaria de bug, mas de decisão de design (aqui feita por ksh, de onde o bash copiou sua sintaxe).

Resposta

Em vez de fundir duas listas, podemos construir a matriz em um único loop (e uma única chamada para awk para uma boa medida) retornando uma lista de entradas de usuário: dir e depois dividindo isso com expansões de variáveis:

#!/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 

Resposta

zsh tem uma função mais útil, mais usual (semelhante a tcl ou perl) maneira de declarar matrizes associativas como um todo: array=(key1 value1 key2 value2...)

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

Duplicação \n, como em ksh93 remove o status especial de nova linha como um caractere de espaço em branco IFS . Sem ele, foo:\nbar:x seria dividido em “foo”, “bar”, “x” em vez de “foo”, “”, “bar”, “x”.

Com , a sintaxe é a mesma estranha que em ksh93: array=([key1]=value1 [key2]=value2), então você não pode obter facilmente a saída de um comando em uma matriz associativa diferente de usar um loop fazendo uma única atribuição de elemento por vez, como outros mostraram.

Observe que bash matrizes associativas ( ao contrário de ksh93 ou zsh) têm uma limitação em que a chave não pode ser a string vazia (não é um problema aqui). Outra limitação, desta vez compartilhado com ksh93 é que nem a chave nem os valores podem conter o byte NUL (também não é um problema aqui).

(o suporte a matrizes associativas era em ksh93 desde o início (1993), adicionado a zsh em 1998 (3.1.5-pws-3) e bash em 2009 ( 4.0))

Comentários

  • Por que você colocou ' \ n ' duas vezes no IFS?
  • @rubystallion veja a edição

Deixe uma resposta

O seu endereço de email não será publicado. Campos obrigatórios marcados com *