A leitura de um arquivo com loop IFS funciona somente quando nenhuma matriz é usada

2

Usando o código a seguir, estou tentando ler um arquivo em uma matriz:

GROUPS=()

while IFS=: read -r g1 g2 g3 g4
do
    GROUPS+=("$g3")
    echo "$g3"
done < /etc/group

Isto não funciona, nem sequer produz nada, no entanto, se eu deixar apenas o eco, ele imprime o conteúdo do arquivo. Contanto que a instrução para adicionar a uma matriz esteja presente em algum lugar no loop, nada será impresso. Parece muito estranho, pois posso fazer isso com outros arquivos sem problemas.

Alguma ideia do que está causando isso? Eu verifiquei com o bash -x e quando a instrução problemática está presente, ela nem entra no loop.

Além disso, no caso de ser relevante, estou executando isso como root.

    
por Luis E 29.06.2016 / 21:04

2 respostas

6

Você escolheu, infelizmente, o nome da matriz que já está reservada pelo bash e é somente leitura , então você não pode alterá-lo.

GROUPS

An array variable containing the list of groups of which the current user is a member. Assignments to GROUPS have no effect and return an error status. If GROUPS is unset, it loses its special properties, even if it is subsequently reset.

Basta usar outro nome e o código deve funcionar.

    
por 29.06.2016 / 21:30
0

Você já tem uma resposta dizendo como fazer isso totalmente no bash com um loop while ... read ... ... Gostaria de sugerir que fazer isso apenas no bash é uma das piores maneiras de fazer isso.

Além disso, ler /etc/group em si não é uma boa idéia porque esse arquivo é apenas uma das possíveis fontes de dados de grupo (outras fontes podem incluir LDAP, Active Directory, winbind, NIS, mysql, pgsql, arquivos db Berkeley, arquivos de grupo extras de libnss-extrausers e muitos mais).

Em vez disso, use a saída de getent group .

Tente isto:

g=( $(getent group | awk -F: '{print $3}') )

ou

g=( $(getent group | cut -d: -f3) )

O método awk é particularmente útil se você quiser combiná-lo com pesquisa de texto fixo ou regular e / ou outros critérios de seleção (por exemplo, $1 == groupname ou $3 >= 500 && $3 <= 1000 )

BTW para, por exemplo, depuração, você pode imprimir os grupos na matriz g com, por exemplo:

# all on one line
echo "${g[@]}"

# one element per line
printf "%s\n" "${g[@]}"

# in a format that can be re-used to define the variable in another
# bash shell or script.
declare -p g

Eu particularmente gosto de declare -p para depuração - ele não mostra apenas o nome da variável (por exemplo, semelhante a echo "foo='$foo'" ), ele também mostra os índices de matriz para variáveis de matriz e tudo é corretamente citado e escapou com contrabarra:

$ g=( $(getent group | awk -F: '$1 ~ /my/ {print $1}') )
$ declare -p g
declare -a g='([0]="mysql" [1]="mythtv")'

BTW typeset é sinônimo de declare que funciona no bash e também alguns outros shells como o ksh.

    
por 30.06.2016 / 11:25

Tags