Wie teste ich, ob eine Variable mehrere nicht leere Zeilen in Bash enthält?

10

Angenommen, ich habe zwei Variablen in bash:

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

Ich möchte erkennen, wann eine Variable tatsächlich mehr als eine Textzeile enthält, ohne zusätzliche nachgestellte Zeilenumbrüche.

Also das:

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

würde drucken yes, und dies:

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

würde drucken no.

Für meinen speziellen Fall glaube ich nicht, dass ich mir Gedanken über das Führen von Leerzeilen machen muss, aber es würde nicht schaden, zu wissen, wie das geht.

Wie kann ich das machen?

jpmc26
quelle
@krowe Danke, aber können Sie dort auf bestimmte Antworten verweisen, die nachgestellte Leerzeilen ignorieren? Ich habe keine gesehen. (Auch den Titel entsprechend bearbeitet.)
jpmc26

Antworten:

5

Die einfachste Lösung, die ich kenne, ist:

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

z.B:

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

Das Obige ignoriert alle Leerzeilen: führend, nachlaufend und innen. Beachten Sie jedoch, dass es nicht möglich ist, eine innere Leerzeile zu haben, wenn nicht mindestens zwei nicht leere Zeilen vorhanden sind. Daher kann ihre Existenz die Frage nicht ändern, ob nach dem Trimmen der führenden und nachfolgenden Leerzeilen mehr als eine Zeile vorhanden ist.

Rici
quelle
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

Weitere Informationen
zum Trimmen / Löschen von Leerzeichen und Leerzeilen mit sed finden Sie unter /programming/16414410/delete-empty-lines-using-sed .

Schreiben Sie nun Ihre if expression ...Verwendung $( ... )in Anführungszeichen, um die Anzahl der Zeilen zu ermitteln, und testen Sie sie anhand der Anzahl:

if ["$ (echo" $ MULTILINE "| sed -re '/ ^ $ / d' | wc -l)" -gt 1]; dann
  Echo 'mehr als eine Zeile'; 
sonst 
  Echo 'einzelne oder keine Zeile'; 
fi
Hannu
quelle
0

Eine geringfügige Änderung dieses Codes sollte dies tun. Sie können es in ein eigenes Skript einfügen, um es wie folgt wiederzuverwenden:

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

Dann können Sie es so verwenden (vorausgesetzt, Sie haben das vorherige Skript benannt 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
quelle
Beim ersten Mal wird ein Syntaxfehler angezeigt fi. Leider stecke ich bei Bash 3.1 (msysgit-Version) fest. Ich sehe nichts, was für mich wie ein Syntaxfehler aussieht, aber offensichtlich fehlt mir etwas. Gedanken?
jpmc26
@ jpmc26 Es war ein Fehler aufgetreten. Ich habe es so aktualisiert, dass es ein externes Skript ist, damit es auch einfacher zu verwenden ist.
Krowe
@ jpmc26 Ich habe einige weitere Überprüfungen hinzugefügt, um andere ungerade Eingaben zu testen.
Krowe
0

Nachgestellte Leerzeilen ignorieren

Hier ist ein Ansatz mit awk:

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

Wie es funktioniert:

  • Echo "$ TEST"

    Dies nimmt jede Shell-Variable, an der wir interessiert sind, und sendet sie an Standard Out.

  • tac

    Dies kehrt die Reihenfolge der Zeilen um, sodass die letzte Zeile zuerst zurückgegeben wird. Nach der Ausführung tacwerden die nachfolgenden Zeilen zu den führenden Zeilen.

    (Der Name tacist die Umkehrung von cataus dem Grund, der tactut, was cattut, aber umgekehrt.)

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

    Dies speichert die Zeilennummer der ersten nicht leeren Zeile in der Variablen f. Nach dem Einlesen aller Zeilen wird fdie Gesamtzahl der Zeilen verglichen NR. Wenn fgleich ist, NRhatten wir nur eine einzige Zeile (wobei die anfänglichen Leerzeichen ignoriert wurden) und beenden mit Code 0. Wenn nach der ersten leeren Zeile eine oder mehrere Zeilen stehen, wird sie mit Code `beendet.

  • && echo "Found A Single Line"

    Wenn awkmit Code 0 beendet, wird die echoAnweisung ausgeführt.

Ignorieren sowohl führender als auch nachfolgender Leerzeilen

Durch Erstellen einer zusätzlichen awkVariablen können wir den Test erweitern, um sowohl führende als auch nachfolgende Leerzeilen zu ignorieren:

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

Da diese Version des awkCodes sowohl führende als auch nachfolgende Leerzeichen verarbeitet, tacwird sie nicht mehr benötigt.

Nehmen Sie den awkCode Stück für Stück:

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

    Wenn die Variable firstNull ist (oder noch nicht festgelegt wurde) und die Zeile ein Zeichen oder ein beliebiges Zeichen enthält, wird firstdie Zeilennummer festgelegt. Wenn awkdas Lesen der Zeilen abgeschlossen ist, firstwird die Zeilennummer der ersten nicht leeren Zeile festgelegt.

  • /./ {last=NR}

    Wenn die Zeile ein Zeichen enthält, setzen Sie die Variable lastauf die aktuelle Zeilennummer. Wenn awkalle Zeilen gelesen sind, hat diese Variable die Zeilennummer der letzten nicht leeren Zeile.

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

    Dies wird ausgeführt, nachdem alle Zeilen gelesen wurden. Wenn firstgleich ist last, haben wir null oder nicht leere Zeilen gesehen und werden awkmit Code beendet 0. Andernfalls wird es mit Code beendet 1. Das Shell-Skript kann den Exit-Code wie gewohnt mit ifAnweisungen oder &&oder testen ||.

John1024
quelle