paulo1205
(usa Ubuntu)
Enviado em 15/01/2018 - 03:59h
Você precisa entender como o shell trata a execução de pipelines e de comandos compostos, especialmente quando há redirecionamento de arquivos.
Essas coisas estão documentadas na manpage de cada shell (e os diferentes sabores de shell têm comportamentos diferentes: aqui, eu vou falar do bash), de modo que, se você ler a sessão relevante, pode tirar suas próprias conclusões.
Sobre pipelines, é importante você notar que cada componente da pipeline executa num processo separado do shell original,
mesmo que seja um comando interno do shell, tal como read ou while. Assim sendo, qualquer alteração de variável que você faça em qualquer parte da pipeline vai acontecer dentro de um processo distinto do original e, portanto, não se refletirá nesse processo. Isso explica a falha na primeira versão do seu programa.
Comandos compostos têm múltiplas formas, incluindo laços de repetição como os de
while ou
for e os de execução condicional, como
if ou
case. O cuidado que você tem de ter com comandos compostos é que eventuais redirecionamentos afetam todos os comandos individuais que compõem o comando composto, e não apenas o comando aparentemente mais externo. Um erro relativamente comum é a pessoa colocar um comando interativo, que deveria pedir confirmação de alguma operação ao usuário, dentro de um laço de repetição que teve a entrada redirecionada, mais ou menos parecido com o seguinte.
while read arquivo; do
rm -i "$arquivo"
done < /tmp/lista_de_arquivos.txt
O erro no código acima é que o comando
rm vai entender que a confirmação de se o arquivo deve ser apagada ou não deve vir da próxima linha do arquivo usado no redirecionamento.
Uma solução, nesse caso, seria redirecionar apenas a leitura do nome do arquivo a ser apagado. Para tanto, poder-se-ia fazer o seguinte.
exec 3</tmp/lista_de_arquivos.txt # Associa arquivo ao descritor nº 3.
while read -u 3 arquivo; do # Manda o read (e não todo o comando composto!) ler especificamente do descritor nº 3.
rm -i "$arquivo"
done
exec 3<&- # Fecha (desativa) o descritor nº 3.
Assim sendo, acho que o melhor modo (i.e. mais seguro, para você poder colocar outras coisas dentro do bloco a ser repetido sem afetar nem ser afetado por redirecionamentos) de reescrever seu programa seria o seguinte.
i=0
exec 3</etc/passwd
while read -u 3 line
do
((++i))
done
exec 3<&-
echo $i