¿Cómo descubrir una nueva línea usando un bucle for?

8

En varios lugares de la web he encontrado:

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

todo como sinónimos de varias líneas nuevas / retornos de carro ...

Pero en este pequeño script no puedo reconocer cuando me encuentro con una nueva línea: ¿alguien puede decirme qué debo verificar en la línea 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
fuente
1
Tengo una pregunta tonta. ¿Por qué necesitas hacer esto? Si lee la entrada línea por línea cat | while read line; do ...; done, sabe que hubo un retorno de carro para cada iteración. Si su entrada puede ser archivos \rsin \n, simplemente transforme el archivo tr '\r' '\n'mientras procesa la entrada. Si sólo necesita saber si hay varias líneas: wc -l.
nicerobot
Bienvenido a Stack Exchange. No edite su pregunta de esta manera, ya que hace que las respuestas existentes no tengan sentido. Como ha encontrado una manera de resolver su problema, puede publicarlo como una respuesta alternativa.
Gilles 'SO- deja de ser malvado'
@nicerobot si no hay línea nueva, wc -ldevolverá 0; deberías agregar eso como respuesta
Arcege
@lolfrog la solución no debe estar en la pregunta, debe marcar la respuesta que tiene la solución
Arcege

Respuestas:

6

Si usa cadenas directamente bajo un forbucle, funcionará por palabra (aquí en una palabra: todo el contenido de $testdesde que se cita), no por carácter. Debe usar un whilebucle con readpara analizar letra por letra o para introducir un parámetro numérico que se repita en la cadena.

Además, al usarlo read, debe asegurarse de que las líneas nuevas y los espacios en blanco no se interpreten como delimitadores y forzar la readlectura de un carácter a la vez.

Aquí hay una versión funcional:

#!/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

Puede reemplazar $'\n'con $'\012'o $'\x0a', ya que todos representan el mismo código de nueva línea. Pero no es lo mismo que \015o \r, esto significa retorno de carro (retorno al comienzo de la línea). En los sistemas Linux, las nuevas líneas se representan usando \n, pero en Windows, por ejemplo, se representan mediante una secuencia de en su \r\nlugar. Es por eso que si tuviera un archivo de texto de Windows, también podría detectar nuevas líneas buscando \r.

rozcietrzewiacz
fuente
En resumen, está convirtiendo la secuencia de escape citada como \nen su representación de bytes, por lo que no necesita colocar saltos de línea de aspecto feo en su declaración de prueba.
rozcietrzewiacz
4

Puede buscar nuevas líneas en una variable muy fácilmente en bash con:

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

Me resulta más conveniente usar:

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

Sugeriría usar try luego test:

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

El tr -cdelimina todo excepto Los saltos de linea / retornos de carro. Si hay nuevas líneas en el archivo, habrá una salida desde la cual la -nprueba devolverá verdadero.

Arcege
fuente
Eso no funcionará para los archivos que no contienen \rs porque la sustitución de comandos elimina los caracteres de línea nueva ( "$(printf '\n\n\n\n\n')"es la cadena vacía).
Stéphane Chazelas