Como descobrir uma nova linha usando um loop for?

8

Em vários lugares da web, encontrei:

\015 
\012
\x0a - hex
\n
\r

tudo como sinônimo de várias novas linhas / retornos de carro ...

Mas neste pequeno script que não consigo reconhecer quando me deparo com uma nova linha - alguém pode me dizer o que devo procurar na linha if?

#!/bin/bash

test="this is a
test"

for a in "$test"; do

        if [[ "$a" == '\012' ]] ; then
                echo "FOUND NEWLINE"
        fi

echo "$a"

done
lolfrog
fonte
1
Eu tenho uma pergunta idiota. Por que você tem que fazer isso? Se você ler a entrada linha por linha cat | while read line; do ...; done, sabe que houve um retorno de carro para cada iteração. Se sua entrada puder ser arquivos \rsem \n, apenas transforme o arquivo tr '\r' '\n'enquanto processa a entrada. Se você só precisa saber se existem várias linhas: wc -l.
Nicerobot
Bem-vindo ao Stack Exchange. Não edite sua pergunta dessa maneira, pois isso torna as respostas existentes sem sentido. Como você encontrou uma maneira de resolver seu problema, você pode publicá-la como uma resposta alternativa.
Gilles 'SO- stop be evil'
@nicerobot se não houver nova linha, wc -lretornará 0; você deve adicionar isso como resposta
Arcege
@lolfrog a solução não deve ser na pergunta, você deve marcar a resposta que tem a solução
Arcege

Respostas:

6

Se você usar diretamente as strings em um forloop, ele funcionará por palavra (aqui em uma palavra: todo o conteúdo $testdesde que foi citado), não por caractere. Você precisa usar um whileloop com readpara analisar letra por letra ou para introduzir um parâmetro numérico que itere sobre a string.

Além disso, ao usar read, você precisa garantir que novas linhas e espaços em branco não sejam interpretados como delimitadores e forçar reada leitura de um caractere de cada vez.

Aqui está uma versão de trabalho:

#!/bin/bash

test="this is a
test"

printf %s "$test" | while IFS= read -r -N 1 a; do

        if [[ "$a" == $'\n' ]] ; then
                echo "FOUND NEWLINE"
        fi

printf %s "$a"

done

Você pode substituir $'\n'por $'\012'ou $'\x0a', pois todos eles representam o mesmo código de nova linha. Mas não é o mesmo que \015ou \r- isso significa retorno de carro (retorno ao início da linha). Nos sistemas Linux, as novas linhas são representadas usando \n, mas no Windows, por exemplo, elas são representadas por uma sequência \r\n. Por isso, se você tiver um arquivo de texto do Windows, poderá detectar novas linhas também pesquisando \r.

rozcietrzewiacz
fonte
Em resumo, está transformando a sequência de escape entre aspas como \nem sua representação de bytes, para que você não precise colocar quebras de linha entre aspas e aparência feia em sua declaração de teste.
rozcietrzewiacz
4

Você pode verificar novas linhas em uma variável muito facilmente no bash com:

[[ $var = *$'\n'* ]]

Acho mais conveniente usar:

declare -r EOL=$'\n' TAB=$'\t' # at top of script
..
if [[ $var = *$EOL* ]]; then # to test (no field-splitting in [[ )
steveL
fonte
1

Eu sugiro usar tre depois test:

if [ -n "$(tr -cd '\n\r' < datafile)" ]; then
    echo "NEWLINE FOUND"
fi

O tr -cdremove tudo, exceto as novas linhas / retornos de carro. Se houver novas linhas no arquivo, haverá saída a partir da qual o -nteste retornará verdadeiro.

Arcege
fonte
Isso não funcionará para arquivos que não contenham \rs porque a substituição de comandos remove os caracteres de nova linha à direita ( "$(printf '\n\n\n\n\n')"é a string vazia).
Stéphane Chazelas