Comment puis-je tester si une variable a plusieurs lignes non vides dans bash?

10

Disons que j'ai deux variables dans bash:

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

Je veux détecter quand une variable contient réellement plus d'une ligne de texte, sans tenir compte des caractères de retour à la ligne supplémentaires.

Donc ça:

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

imprimerait yes, et ceci:

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

imprimerait no.

Pour mon cas spécifique, je ne pense pas avoir besoin de m'inquiéter des lignes blanches en tête, mais cela ne ferait pas de mal de savoir comment faire cela.

Comment puis-je faire ceci?

jpmc26
la source
@krowe Merci, mais pouvez-vous indiquer des réponses spécifiques qui ignorent les lignes vides de fin? Je n'en ai pas vu. (A également modifié le titre en conséquence.)
jpmc26

Réponses:

5

La solution la plus simple que je connaisse est:

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

par exemple:

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

Ce qui précède ignore toutes les lignes vides: en tête, en queue et intérieur. Mais notez qu'il n'est pas possible d'avoir une ligne vide intérieure à moins qu'il y ait au moins deux lignes non vides, donc son existence ne peut pas changer la question de savoir s'il y a plus d'une ligne après avoir coupé les lignes vides de début et de fin.

rici
la source
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

Voir /programming/16414410/delete-empty-lines-using-sed
pour en savoir plus sur la façon de couper / supprimer les espaces et les lignes vides à l'aide de sed.

Maintenant, écrivez votre if expression ...utilisation entre $( ... )guillemets pour obtenir le nombre de lignes et testez le nombre:

if ["$ (echo" $ MULTILINE "| sed -re '/ ^ $ / d' | wc -l)" -gt 1]; puis
  l'écho «plus d'une ligne»; 
autre 
  écho «simple ou pas de ligne»; 
Fi
Hannu
la source
0

Une légère modification de ce code devrait le faire. Vous pouvez le mettre dans son propre script pour une réutilisation comme ceci:

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

Ensuite, vous pouvez l'utiliser comme ça (en supposant que vous avez nommé le script précédent 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
la source
Je reçois une erreur de syntaxe le premier fi. Malheureusement, je suis bloqué sur bash 3.1 (version msysgit). Je ne vois rien qui ressemble à une erreur de syntaxe pour moi, mais évidemment, il me manque quelque chose. Pensées?
jpmc26
@ jpmc26 Il y avait une erreur. Je l'ai mis à jour pour être un script externe afin qu'il soit également plus facile à utiliser.
krowe
@ jpmc26 J'ai ajouté quelques vérifications supplémentaires pour tester d'autres entrées impaires.
krowe
0

Ignorer les lignes vides de fin

Voici une approche utilisant awk:

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

Comment ça fonctionne:

  • écho "$ TEST"

    Cela prend la variable shell qui nous intéresse et l'envoie à la sortie standard.

  • tac

    Cela inverse l'ordre des lignes afin que la dernière ligne soit renvoyée en premier. Après l'exécution tac, les lignes de fin deviennent les lignes de tête.

    (Le nom tacest l'inverse de catpour la raison qui tacfait ce que catfait mais à l'envers.)

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

    Cela stocke le numéro de ligne de la première ligne non vide dans la variable f. Après avoir lu dans toutes les lignes, il se compare fau nombre total de lignes, NR. si fest égal à NR, alors nous n'avions qu'une seule ligne (en ignorant les blancs initiaux) et nous sortons avec le code 0. S'il y avait une ou plusieurs lignes après la première ligne vide, alors il se termine avec le code `.

  • && echo "Found A Single Line"

    En cas de awksortie avec le code 0, l' echoinstruction est exécutée.

Ignorer les lignes vides de début et de fin

En créant une awkvariable supplémentaire , nous pouvons étendre le test pour ignorer les lignes vides de début et de fin:

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

Parce que cette version du awkcode gère à la fois les blancs de début et de fin, tacn'est plus nécessaire.

Prendre le awkcode morceau par morceau:

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

    Si la variable firstest zéro (ou si elle n'a pas encore été définie) et que la ligne a un caractère, n'importe quel caractère, alors définissez firstle numéro de ligne. Une fois la awklecture des lignes terminée, firstsera défini sur le numéro de ligne de la première ligne non vide.

  • /./ {last=NR}

    Si la ligne contient un caractère, définissez la variable lastsur le numéro de ligne actuel. Lorsque la awklecture de toutes les lignes est terminée, cette variable aura le numéro de ligne de la dernière ligne non vide.

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

    Ceci est exécuté après que toutes les lignes ont été lues. Si firstest égal à last, alors nous avons vu zéro ou des lignes non vides et des awksorties avec du code 0. Sinon, il se termine avec du code 1. Le script shell peut tester le code de sortie comme d'habitude avec des ifinstructions ou &&ou ||.

John1024
la source