Seu principal problema é que o último comando em um pipeline é executado em um subshell, como todos os outros comandos no pipeline. Este é o caso da maioria dos shells. ATT ksh e zsh são exceções: eles executam o último comando do pipeline no shell pai.
Desde o bash 4.2, você pode dizer ao bash para se comportar como ksh e zsh, definindo o lastpipe
opção .
#!/bin/bash
USERS=()
shopt -s lastpipe
w | awk '{if(NR > 2) print $1,$2,$3}' | while read line; do
USERS+=("$line")
done
echo ${#USERS[@]}
Como alternativa, você pode usar a substituição de processo em vez de um canal. que o comando read
é executado no processo principal do shell.
#!/bin/bash
USERS=()
while read line; do
USERS+=("$line")
done < <(w | awk '{if(NR > 2) print $1,$2,$3}')
echo ${#USERS[@]}
Como alternativa, você pode usar a abordagem portável, que funciona em shells que não têm comportamento de processo nem em ksh / zsh, como Bourne, dash e pdksh. (Você ainda precisa de (pd) ksh, bash ou zsh para matrizes.) Execute tudo o que requer os dados do pipeline dentro do pipeline.
#!/bin/bash
USERS=()
shopt -s lastpipe
w | awk '{if(NR > 2) print $1,$2,$3}' | {
while read line; do
USERS+=("$line")
done
echo ${#USERS[@]}
}