Como testar se uma variável possui várias linhas não vazias no bash?

10

Digamos que eu tenha duas variáveis ​​no bash:

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

Quero detectar quando uma variável realmente contém mais de uma linha de texto, desconsiderando caracteres extras de nova linha à direita.

Então, é isso:

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

seria impresso yes, e isso:

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

iria imprimir no.

Para o meu caso específico, acho que não preciso me preocupar com linhas em branco à esquerda, mas não faria mal saber como fazer isso.

Como posso fazer isso?

jpmc26
fonte
@krowe Obrigado, mas você pode apontar para respostas específicas que ignoram as linhas em branco à direita? Eu não vi nenhum. (Também editado o título em conformidade.)
jpmc26

Respostas:

5

A solução mais simples que conheço é:

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

por exemplo:

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

O item acima ignora todas as linhas em branco: inicial, final e interior. Mas observe que não é possível ter uma linha em branco interior, a menos que haja pelo menos duas linhas que não sejam em branco; portanto, sua existência não pode alterar a questão de saber se há mais de uma linha após aparar as linhas em branco à esquerda e à direita.

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

$ echo "$ SINGLE_LINE" | wc -l
2

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

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

Consulte /programming/16414410/delete-empty-lines-using-sed
para obter mais informações sobre como aparar / excluir espaços em branco e linhas vazias usando sed.

Agora, escreva seu if expression ...uso entre $( ... )aspas para obter o número de linhas e teste com o número:

if ["$ (eco" $ MULTILINE "| sed -re '/ ^ $ / d' | wc -l)" -gt 1]; então
  eco 'mais de uma linha'; 
outro 
  eco 'linha única ou sem linha'; 
fi
Hannu
fonte
0

Uma ligeira modificação neste código deve fazê-lo. Você pode colocá-lo em seu próprio script para reutilizar assim:

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

Em seguida, você pode usá-lo dessa maneira (assumindo que você nomeou o 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
fonte
Estou recebendo um erro de sintaxe no primeiro fi. Infelizmente, estou preso no bash 3.1 (versão msysgit). Não vejo nada que pareça um erro de sintaxe para mim, mas obviamente estou perdendo alguma coisa. Pensamentos?
Jpmc26
@ jpmc26 Ocorreu um erro. Atualizei-o para ser um script externo, para que também seja mais fácil de usar.
krowe
@ jpmc26 Adicionei mais algumas verificações para testar outras entradas ímpares.
precisa saber é
0

Ignorando as linhas em branco à direita

Aqui está uma abordagem usando awk:

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

Como funciona:

  • eco "$ TEST"

    Isso pega qualquer variável do shell em que estamos interessados ​​e a envia para o padrão.

  • tac

    Isso reverte a ordem das linhas para que a última linha seja retornada primeiro. Após a execução tac, as linhas finais tornam-se as linhas principais.

    (O nome tacé o reverso de catpelo motivo que tacfaz o que catfaz, mas ao contrário.)

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

    Isso armazena o número da primeira linha que não está em branco na variável f. Depois de ler todas as linhas, ele se compara fao número total de linhas NR,. se ffor igual a NR, teríamos apenas uma única linha (ignorando espaços em branco iniciais) e sairemos com o código 0. Se houver uma ou mais linhas após a primeira linha em branco, ela sairá com o código `.

  • && echo "Found A Single Line"

    Se awksair com o código 0, a echoinstrução será executada.

Ignorando linhas em branco iniciais e finais

Ao criar uma awkvariável adicional , podemos estender o teste para ignorar as linhas em branco à esquerda e à direita:

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

Como esta versão do awkcódigo lida com espaços em branco à esquerda e à direita, tacnão é mais necessária.

Tomando o awkcódigo um pedaço de cada vez:

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

    Se a variável firstfor zero (ou ainda não foi definida) e a linha tiver um caractere, qualquer caractere, defina firsto número da linha. Quando awkterminar de ler as linhas, firstserá definido como o número da linha da primeira linha que não estiver em branco.

  • /./ {last=NR}

    Se a linha tiver algum caractere, defina a variável lastcomo o número da linha atual. Quando awkterminar de ler todas as linhas, essa variável terá o número da última linha que não estiver em branco.

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

    Isso é executado depois que todas as linhas foram lidas. Se firstfor igual a last, vimos zero ou linha linhas não em branco e awksai com o código 0. Caso contrário, ele sai com o código 1. O script de shell pode testar o código de saída normalmente com ifinstruções ou &&ou ||.

John1024
fonte