Come posso verificare se una variabile ha più righe non vuote in bash?


10

Supponiamo di avere due variabili in bash:

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

Voglio rilevare quando una variabile contiene in realtà più di una riga di testo, ignorando i caratteri di nuova riga finali in più.

Così questo:

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

stamperebbe yes, e questo:

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

stamperebbe no.

Per il mio caso specifico, non penso di dovermi preoccupare di iniziare le righe vuote, ma non sarebbe male sapere come farlo.

Come posso fare questo?



@krowe Grazie, ma puoi indicare lì risposte specifiche che ignorano le righe vuote in coda? Non ne ho visto nessuno. (Anche modificato il titolo di conseguenza.)
jpmc26

Risposte:


5

La soluzione più semplice che conosco è:

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

per esempio:

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

Quanto sopra ignora tutte le righe vuote: iniziale, finale e interno. Ma nota che non è possibile avere una linea vuota interna se non ci sono almeno due linee non vuote, quindi la sua esistenza non può alterare la questione se ci siano più di una linea dopo il taglio delle linee vuote iniziali e finali.


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

Vedi /programming/16414410/delete-empty-lines-using-sed
per ulteriori informazioni su come tagliare / eliminare gli spazi bianchi e le linee vuote usando sed.

Ora per scrivere il tuo if expression ...uso $( ... )tra virgolette per ottenere il numero di righe e testare contro il numero:

if ["$ (echo" $ MULTILINE "| sed -re '/ ^ $ / d' | wc -l)" -gt 1]; poi
  echo "più di una riga"; 
altro 
  echo 'single or no line'; 
fi

0

Una leggera modifica a questo codice dovrebbe farlo. Puoi metterlo nel suo script per il riutilizzo in questo modo:

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

Quindi puoi usarlo in questo modo (supponendo che tu abbia chiamato lo script precedente 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

Ricevo un errore di sintassi sul primo fi. Sfortunatamente, sono bloccato su bash 3.1 (versione msysgit). Non vedo nulla che mi sembri un errore di sintassi, ma ovviamente mi manca qualcosa. Pensieri?
jpmc26,

@ jpmc26 Si è verificato un errore. Ho aggiornato per essere uno script esterno in modo che sia anche più facile da usare.
Krowe,

@ jpmc26 Ho aggiunto altri controlli per testare altri input dispari.
Krowe,

0

Ignorando le righe vuote finali

Ecco un approccio usando awk:

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

Come funziona:

  • echo "$ TEST"

    Questo prende qualunque variabile di shell a cui siamo interessati e la manda fuori standard.

  • tac

    Ciò inverte l'ordine delle linee in modo che l'ultima riga venga restituita per prima. Dopo l'esecuzione tac, le linee finali diventano le linee principali.

    (Il nome tacè il contrario di catper la ragione che tacfa ciò che catfa ma al contrario.)

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

    Ciò memorizza il numero di riga della prima riga non vuota nella variabile f. Dopo aver letto in tutte le linee, confronta fil numero totale di linee, NR. se fè uguale a NR, allora avevamo solo una riga (ignorando gli spazi iniziali) e usciamo con il codice 0. Se c'erano una o più righe dopo la prima riga vuota, allora esce con il codice `.

  • && echo "Found A Single Line"

    Se awkuscito con il codice 0, l' echoistruzione viene eseguita.

Ignorando le righe vuote sia in testa che in coda

Creando una awkvariabile aggiuntiva , possiamo estendere il test per ignorare le righe vuote sia iniziali che finali:

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

Poiché questa versione del awkcodice gestisce gli spazi vuoti sia iniziali che finali, tacnon è più necessario.

Prendendo il awkcodice un pezzo alla volta:

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

    Se la variabile firstè zero (o non è stata ancora impostata) e la riga ha un carattere, qualsiasi carattere, quindi impostare firstil numero di riga. Al awktermine della lettura delle righe, firstverrà impostato il numero di riga della prima riga non vuota.

  • /./ {last=NR}

    Se la riga contiene caratteri, imposta la variabile lastsul numero di riga corrente. Al awktermine della lettura di tutte le righe, questa variabile avrà il numero di riga dell'ultima riga non vuota.

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

    Questo è stato eseguito dopo che tutte le righe sono state lette. Se firstè uguale a last, allora abbiamo visto zero o line righe non vuote ed awkesce con il codice 0. Altrimenti, esce con il codice 1. Lo script della shell può testare il codice di uscita come al solito con ifistruzioni o &&o ||.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.