Você faria:
while IFS= read -r url || [ -n "$url" ]; do
printf '%s\n' "$url"
done < url.list
(efetivamente, esse loop adiciona de volta a nova linha ausente na última (não) linha).
Veja também:
Eu tenho um arquivo chamado /tmp/urlFile
, onde cada linha representa um URL. Eu estou tentando ler o arquivo da seguinte maneira:
cat "/tmp/urlFile" | while read url
do
echo $url
done
Se a última linha não terminar com um caractere de nova linha, essa linha não será lida. Eu estava me perguntando por que?
É possível ler todas as linhas, independentemente de terminarem com uma nova linha ou não?
Você faria:
while IFS= read -r url || [ -n "$url" ]; do
printf '%s\n' "$url"
done < url.list
(efetivamente, esse loop adiciona de volta a nova linha ausente na última (não) linha).
Veja também:
Isso parece ser resolvido em parte com readarray -t
:
readarray -t urls "/tmp/urlFile"
for url in "${urls[@]}"; do
echo "$url"
done
Observe, entretanto, que embora isso funcione para arquivos de tamanho razoável, esta solução apresenta um novo problema em potencial com arquivos muito grandes - ele primeiro lê o arquivo em uma matriz que, em seguida, deve ser iterada. Para arquivos muito grandes, isso pode consumir tanto o tempo quanto a memória, potencialmente até o ponto de falha.
Por definição , um arquivo de texto consiste em uma sequência de linhas. Uma linha termina com um caractere de nova linha. Assim, um arquivo de texto termina com um caractere de nova linha, a menos que esteja vazio.
O read
builtin destina-se apenas a ler arquivos de texto. Você não está passando um arquivo de texto, então você não pode esperar que ele funcione perfeitamente. O shell lê todas as linhas - o que está pulando são os caracteres extras depois da última linha.
Se você tem um arquivo de entrada potencialmente malformado que pode estar faltando sua última linha, você pode adicionar uma nova linha a ele, só para ter certeza.
{ cat "/tmp/urlFile"; echo; } | …
Os arquivos que devem ser arquivos de texto, mas não possuem a nova linha final, são geralmente produzidos pelos editores do Windows. Isso geralmente ocorre em combinação com os finais de linha do Windows, que são CR LF, em oposição ao LF do Unix. Os caracteres CR raramente são úteis em qualquer lugar e não podem aparecer em URLs, portanto, você deve removê-los.
{ <"/tmp/urlFile" tr -d '\r'; echo; } | …
Caso o arquivo de entrada seja bem formado e termine com uma nova linha, o echo
adiciona uma linha extra em branco. Como as URLs não podem estar vazias, basta ignorar as linhas em branco.
Observe também que read
não lê linhas de maneira simples. Ele ignora espaços em branco iniciais e finais, o que, para uma URL, é provavelmente desejável. Ele trata a barra invertida no final de uma linha como um caractere de escape, fazendo com que a próxima linha seja unida à primeira menos a seqüência de barra invertida-nova linha, o que definitivamente não é desejável. Então você deve passar a opção -r
para read
. É muito raro que read
seja a coisa certa em vez de read -r
.
{ <"/tmp/urlFile" tr -d '\r'; echo; } | while read -r url
do
if [ -z "$url" ]; then continue; fi
…
done
Bem, read
retorna um valor falsy se encontrar o fim do arquivo antes de uma nova linha, mas mesmo assim, ele ainda atribui o valor lido. Assim, podemos verificar se a chamada final de read
retorna algo diferente de uma linha vazia e processá-la normalmente. Então, apenas saia do loop após read
retornar false e a linha estiver vazia:
#!/bin/sh
while IFS= read -r line || [ "$line" ]; do
echo "line: $line"
done
$ printf 'foo\nbar' | sh ./read.sh
line: foo
line: bar
$ printf 'foo\nbar\n' | sh ./read.sh
line: foo
line: bar
Outra maneira seria assim:
When read reaches end-of-file instead of end-of-line, it does read in the data and assign it to the variables, but it exits with a non-zero status. If your loop is constructed "while read ;do stuff ;done
So instead of testing the read exit status directly, test a flag, and have the read command set that flag from within the loop body. That way regardless of reads exit status, the entire loop body runs, because read was just one of the list of commands in the loop like any other, not a deciding factor of if the loop will get run at all.
DONE=false
until $DONE ;do
read || DONE=true
echo $REPLY
done < /tmp/urlFile
Referido de aqui .
cat "/tmp/urlFile" | while read url do echo $url done
Este é um Uso inútil de cat
.
Ironicamente, você pode substituir o processo cat
aqui por algo realmente útil: uma ferramenta que os sistemas POSIX têm para adicionar a nova linha perdida e fazer o arquivo em um arquivo de texto POSIX adequado.
sed -e '$a\' "/tmp/urlFile" | while read -r url do printf "%s\n" "${url}" done
Tags bash text-processing shell newlines