O que 'while read -r line || [[-n $ line]] 'significa?

2

Encontrei algum código para ler a entrada de um arquivo há algum tempo, acredito, do Stack Exchange, que consegui me adaptar às minhas necessidades:

while read -r line || [[ -n "$line" ]]; do
    if [[ $line != "" ]]
    then
        ((x++));
        echo "$x:  $line"
    <then do something with $line>
    fi
done < "$1"

Estou revisando meu script agora & tentando entender o que está fazendo ... não entendo o que esta declaração está fazendo:

while read -r line || [[ -n "$line" ]];

Entendo que a opção -r diz que estamos lendo texto bruto na linha, mas estou confuso sobre a parte || [[ -n "$line" ]] da instrução. Alguém pode, por favor, explicar o que isso está fazendo?

    
por K. Hilbert 30.10.2018 / 19:44

2 respostas

2

[[ -n "$line" ]] testa se $line (a variável acabou de ler por read ) não está vazia. É útil, pois read retorna um sucesso se e somente se vir um caractere de nova linha antes do fim do arquivo. Se a entrada contiver um fragmento de linha sem uma nova linha no final, esse teste detectará isso e o loop também processará essa linha final incompleta. Sem o teste extra, essa linha incompleta seria lida em $line , mas ignorada pelo loop.

A construção cmd1 || cmd2 é, é claro, igual ao equivalente em C. O segundo comando é executado se o primeiro retornar um status falso e o resultado é o status de saída do último comando executado.

Compare:

$ printf 'foo\nbar' | ( while read line; do echo "in loop: $line" ; done ; echo "finally: $line" )
in loop: foo
finally: bar

e

$ printf 'foo\nbar' | ( while read line || [[ -n $line ]]; do echo "in loop: $line" ; done ; echo "finally: $line" )
in loop: foo
in loop: bar
finally: 
    
por 30.10.2018 / 20:51
1

É um pouco confuso sobre por que isso estaria lá, mas é fácil explicar o que ele faz: || é uma instrução OR e [[ -n retorna verdadeiro (sucesso) contanto que "$line" tem um comprimento diferente de zero. Aqui está o que é confuso: enquanto loops continuam enquanto há um status de saída bem-sucedido (0). read continua a ler linhas e retorna um status de saída 0 até atingir o final do arquivo - mesmo que essas linhas estejam em branco. [[ -n "$line" ]] só será executado quando read retornar um código de saída diferente de zero, no qual $line estará vazio. Como o teste retorna true se $line não estiver vazio , voltaremos a uma saída diferente de zero, nos jogando fora do loop while . Até onde eu posso ver, || [[ -n "$line" ]] na verdade não realiza nada. (Como apontado por @ilkkachu, isso vai pegar a estranha linha final de entrada que está faltando em sua nova linha. um arquivo não é um arquivo de texto válido, já que a linha não é uma linha válida

Algo que é ocasionalmente útil é fazer while read -r line && [[ -n "$line" ]] . Usar && (AND) significa que toda a instrução retornará apenas um status zero se read for capaz de ler uma linha E que a linha não está vazia. Isso fará com que o loop while seja interrompido na primeira linha vazia. Se eu tivesse que adivinhar, esse trecho de código pode ter sido adaptado de um que fez exatamente isso - e em vez de simplesmente remover o teste, o autor alterou o && para || .

    
por 30.10.2018 / 20:42

Tags