¿Cómo pruebo si una variable tiene varias líneas no en blanco en bash?

10

Digamos que tengo dos variables en bash:

MULTILINE="I have
more than one line"
SINGLE_LINE="I only have one line
"

Quiero detectar cuándo una variable realmente contiene más de una línea de texto, sin tener en cuenta los caracteres adicionales de línea nueva.

Así que esto:

if [ some test on "$MULTILINE" ]; then echo 'yes'; else echo 'no'; fi

imprimiría yes, y esto:

if [ some test on "$SINGLE_LINE" ]; then echo 'yes'; else echo 'no'; fi

imprimiría no.

Para mi caso específico, no creo que deba preocuparme por las líneas en blanco, pero no estaría de más saber cómo hacerlo.

¿Cómo puedo hacer esto?

jpmc26
fuente
@krowe Gracias, pero ¿puedes señalar respuestas específicas allí que ignoren las líneas en blanco al final? No vi ninguno. (También editó el título en consecuencia.)
jpmc26

Respuestas:

5

La solución más simple que conozco es:

if (( $(grep -c . <<<"$MULTILINE") > 1 ))

p.ej:

VAR="a
b"
if (( $(grep -c . <<<"$VAR") > 1 )); then
  echo VAR has more than one line
else
  echo VAR has at most one line
fi

==>

VAR has more than one line

Lo anterior ignora todas las líneas en blanco: iniciales, finales e interiores. Pero tenga en cuenta que no es posible tener una línea en blanco interior a menos que haya al menos dos líneas no en blanco, por lo que su existencia no puede alterar la cuestión de si hay más de una línea después de recortar las líneas en blanco iniciales y finales.

rici
fuente
5
$ echo "$ MULTILINE" | wc -l
2

$ echo "$ SINGLE_LINE" | wc -l
2

$ echo "$ SINGLE_LINE" | sed -re '/ ^ $ / d' | wc -l
1

$ echo "$ MULTILINE" | sed -re '/ ^ $ / d' | wc -l
2

Consulte /programming/16414410/delete-empty-lines-using-sed
para obtener más información sobre cómo recortar / eliminar espacios en blanco y líneas vacías con sed.

Ahora para escribir su if expression ...uso $( ... )entre comillas para obtener el número de líneas, y probar contra el número:

if ["$ (echo" $ MULTILINE "| sed -re '/ ^ $ / d' | wc -l)" -gt 1]; entonces
  echo 'más de una línea'; 
más 
  echo 'línea simple o sin línea'; 
fi
Hannu
fuente
0

Una ligera modificación a este código debería hacerlo. Puede ponerlo en su propio script para reutilizarlo así:

#!/bin/bash
nlhit=""
for (( i=0; i<${#1}; i++ )); do
    if [[ "${1:$i:1}" == $'\n' ]]; then
        nlhit="1"
    elif [[ "$nlhit" == "1" ]]; then
        exit 1
    fi
done

exit 0

Luego puede usarlo así (suponiendo que haya nombrado el script anterior multiline-check.sh):

#!/bin/bash

EMPTYLINE=""
BLANKLINE="    "
ONLYLINES="


"

MULTILINE="I have
more than one line"
SINGLE_LINE="I only have one line
"
SECOND_LINE="
I begin with a newline"


echo -n "EMPTYLINE Check: "
multiline-check.sh "$EMPTYLINE"
if [ $? -eq 1 ]; then echo "Yes"; else echo "No"; fi

echo -n "BLANKLINE Check: "
multiline-check.sh "$BLANKLINE"
if [ $? -eq 1 ]; then echo "Yes"; else echo "No"; fi

echo -n "ONLYLINES Check: "
multiline-check.sh "$ONLYLINES"
if [ $? -eq 1 ]; then echo "Yes"; else echo "No"; fi

echo -n "MULTILINE Check: "
multiline-check.sh "$MULTILINE"
if [ $? -eq 1 ]; then echo "Yes"; else echo "No"; fi

echo -n "SINGLE_LINE Check: "
multiline-check.sh "$SINGLE_LINE"
if [ $? -eq 1 ]; then echo "Yes"; else echo "No"; fi

echo -n "SECOND_LINE Check: "
multiline-check.sh "$SECOND_LINE"
if [ $? -eq 1 ]; then echo "Yes"; else echo "No"; fi
krowe
fuente
Recibo un error de sintaxis el primero fi. Desafortunadamente, estoy atascado en bash 3.1 (versión msysgit). No veo nada que me parezca un error de sintaxis, pero obviamente me falta algo. Pensamientos?
jpmc26
@ jpmc26 Tenía un error. Lo actualicé para que sea un script externo para que también sea más fácil de usar.
krowe
@ jpmc26 He agregado algunas comprobaciones más para probar otras entradas impares.
krowe
0

Ignorando las líneas en blanco al final

Aquí hay un enfoque usando awk:

echo "$TEST" | tac | awk 'f==0 && /./ {f=NR} END{if(f==NR){exit 0}; exit 1 }' && echo "Found A Single Line"

Cómo funciona:

  • echo "$ PRUEBA"

    Esto toma cualquier variable de shell que nos interese y la envía al estándar.

  • tac

    Esto invierte el orden de las líneas para que la última línea se devuelva primero. Después de ejecutar tac, las líneas finales se convierten en las líneas principales.

    (El nombre taces el reverso de catpor la razón que tachace lo que cathace pero a la inversa).

  • awk 'f==0 && /./ {f=NR} END{if(f==NR){exit 0}; exit 1 }'

    Esto almacena el número de línea de la primera línea no en blanco en la variable f. Después de leer en todas las líneas, se compara fcon el número total de líneas, NR. si fes igual a NR, entonces teníamos una sola línea (ignorando los espacios en blanco iniciales) y salimos con el código 0. Si había una o más líneas después de la primera línea en blanco, entonces sale con el código '.

  • && echo "Found A Single Line"

    Si awksalió con el código 0, echose ejecuta la instrucción.

Ignorando las líneas en blanco iniciales y finales

Al crear una awkvariable adicional , podemos extender la prueba para ignorar las líneas en blanco iniciales y finales:

echo "$TEST" | awk 'first==0 && /./ {first=NR} /./ {last=NR} END{if(first==last){exit 0}; exit 1 }' && echo " Found A Single Line"

Debido a que esta versión del awkcódigo maneja los espacios en blanco iniciales y finales, tacya no es necesaria.

Tomando el awkcódigo pieza por pieza:

  • first==0 && /./ {first=NR}

    Si la variable firstes cero (o aún no se ha establecido) y la línea tiene un carácter, cualquier carácter, se establece firsten el número de línea. Cuando awktermine de leer las líneas, firstse establecerá el número de línea de la primera línea que no esté en blanco.

  • /./ {last=NR}

    Si la línea tiene algún carácter, establezca la variable lasten el número de línea actual. Cuando awktermine de leer todas las líneas, esta variable tendrá el número de línea de la última línea no en blanco.

  • END{if(first==last){exit 0}; exit 1 }

    Esto se ejecuta después de haber leído todas las líneas. Si firstes igual a last, entonces hemos visto cero o líneas no en blanco y awksalidas con código 0. De lo contrario, sale con código 1. El script de shell puede probar el código de salida como de costumbre con ifsentencias o &&o ||.

John1024
fuente