read retorna um status de saída diferente de zero se não encontrar um delimitador, o que é sempre o caso quando o delimitador é uma string vazia.
Eu tenho usado o padrão abaixo para imprimir mensagens de várias linhas no terminal em um script bash.
read -d '' message <<- EOF
this is a
mulitline
message
EOF
echo "$message"
Isso tem funcionado - até poucos dias atrás, o padrão simplesmente parou de funcionar. Ao parar de funcionar, quero dizer quando bash encontrou essas expressões heredoc no script - parece não fazer nada - sem saída.
A única coisa que posso pensar sobre isso mudou nos últimos dias é que o ambiente em que os scripts são executados é um Ubuntu live USB 14.04, versus instalações "completas".
Então eu descobri que quando eu movia o heredoc antes da declaração set -o errexit dos scripts ele começou a funcionar novamente. ou seja, isso não funciona
#!/bin/bash
set -o errexit
read -d '' message <<- EOF
this is a
mulitline
message
EOF
echo "$message"
resultado: (nada)
Mas isso funciona
#!/bin/bash
read -d '' message <<- EOF
this is a
mulitline
message
EOF
echo "$message"
resultado
$ sudo ./script.sh
this is a
mulitline
message
GNU bash, version 4.3.11(1)-release (i686-pc-linux-gnu)
O código de saída do comando de leitura é 1 quando o marcador de fim de arquivo (EOF) é atingido. Isso sempre ocorrerá quando o delimitador -d for nulo '' neste caso especial em que o fluxo de origem é um heredoc que não pôde conter um \ 0.
$ read -d '' message <<-_ThisMessageEnds_
> this is a
> multi line
> message
> _ThisMessageEnds_
$ exitval=$?
$ echo "The exit val was $exitval"
The exit val was 1.
Se o valor de saída for um erro (não 0), a saída do script pode ser evitada com uma construção AND / OR:
read -d '' message <<-_ThisMessageEnds_ || echo "$message"
this is a
multi line
message
_ThisMessageEnds_
Isso enviará a mensagem para o console e evitará que saia com errexit .
Mas, como estamos nesse caminho para reduzir, por que não usar isso diretamente:
cat <<-_ThisMessageEnds_
this is a
mulitline
message
_ThisMessageEnds_
Nenhum comando de leitura executado (mais velocidade), nenhuma variável necessária, nenhum erro do código de saída, menos código para manter.
read -d '' message
lê stdin até o primeiro caractere NUL sem escape (como você não adicionou -r ) ou o final da entrada e armazena os dados após $IFS e processamento de caracteres de barra invertida em $message (sem o delimitador).
Se nenhum delimitador sem escape for encontrado na entrada, o status de saída read será diferente de zero. Apenas retorna 0 (sucesso) se um registro completo e terminado for lido.
É mais útil para lidar com registros delimitados por NUL, como a saída de find -print0 (embora você precise de uma sintaxe IFS= read -rd '' record ).
Aqui, você precisa incluir um delimitador NUL em seu documento aqui para que read retorne com êxito. Isso, no entanto, não é possível com bash , que tira os caracteres NUL dos documentos here (que é pelo menos melhor que yash que retira tudo além do primeiro NUL, ou ksh93, que parece entrar em um loop infinito quando um documento aqui contém um NUL).
zsh é o único shell que pode ter um NUL em seus documentos aqui ou armazená-lo em suas variáveis ou passar caracteres NUL em argumentos para seus builtins / funções. Em zsh , você pode fazer:
NUL=$'ONE=$''
IFS= read -d "$ONE" -r var << EOF
1
2
3$ONE
EOF
'
IFS= read -d $NUL -r var << EOF
1
2
3$NUL
EOF
( zsh também entende read -d '' como um delimitador NUL como bash . read -d $' também funciona em bash'read , mas que transmite um argumento vazio para read -d '' , como em bash as $NUL não suporta bytes NUL em sua linha de comando).
(observe que há um caractere extra de nova linha depois disso bash )
Em read -d , você pode usar um caractere diferente:
var=$(cat <<EOF
message
here
EOF
)
Mas você também pode fazer:
read -d '' message
Isso ainda não permitirá caracteres NUL. No entanto, esse é o código padrão, portanto, você não precisa confiar no ksh93 do zsh / bash específico. Observe também que ele remove todos os caracteres de nova linha à direita e, exceto em cat quando o %code% builtin está ativado, isso significa gerar um processo e um comando extra.
Quando você usa set -o errexit e seu script quebra, significa que há algo errado.
Aqui, é read , que não consegue ler corretamente sua entrada.
Em bash , quando você usa read -d '' , o read builtin usará o caractere nulo como terminador de linha. Portanto, quando não houver readmessage em sua entrada, 1 lerá toda a entrada na variável read e retornará um status de saída diferente de zero para indicar que houve um erro:
$ while read -d '' line; do echo "$line"; done < <(printf '1')
imprime nada enquanto:
$ while read -d '' line; do echo "$line"; done < <(printf '1$ while read -d '' line; do echo "$line"; done < <(printf '1')
')
1
fornece read .
while também retornará status diferente de zero quando atingir EOF, mas é usado para indicar que não há mais entrada para ler quando você usa while com um loop %code% , portanto, o loop %code% pode ser terminado. Não é relevante para o seu problema.
Tags bash