Как проверить, имеет ли переменная несколько непустых строк в bash?

10

Скажем, у меня есть две переменные в bash:

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

Я хочу определить, когда переменная на самом деле содержит более одной строки текста, не обращая внимания на дополнительные завершающие символы новой строки.

Итак, это:

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

будет печатать yes, и это:

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

будет печатать no.

В моем конкретном случае я не думаю, что мне нужно беспокоиться о пустых строках, но не помешало бы узнать, как это сделать.

Как я могу это сделать?

jpmc26
источник
@krowe Спасибо, но можете ли вы указать конкретные ответы, которые игнорируют висячие пустые строки? Я не видел никого. (Также отредактировал название соответственно.)
jpmc26

Ответы:

5

Самое простое из известных мне решений:

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

например:

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

Выше игнорируются все пустые строки: начальные, конечные и внутренние. Но обратите внимание, что внутренняя пустая строка невозможна, если нет хотя бы двух непустых строк, поэтому ее существование не может изменить вопрос о том, существует ли более одной строки после обрезания начальных и конечных пустых строк.

RICi
источник
5
$ echo "$ MULTILINE" | туалет
2

$ echo "$ SINGLE_LINE" | туалет
2

$ echo "$ SINGLE_LINE" | sed -re '/ ^ $ / d' | туалет
1

$ echo "$ MULTILINE" | sed -re '/ ^ $ / d' | туалет
2

См. Https://stackoverflow.com/questions/16414410/delete-empty-lines-using-sed
для получения дополнительной информации о том, как обрезать / удалять пробелы и пустые строки, используя sed.

Теперь напишите ваше if expression ...использование $( ... )внутри кавычек, чтобы получить количество строк, и сравните с числом:

if ["$ (echo" $ MULTILINE "| sed -re '/ ^ $ / d' | wc -l)" -gt 1]; тогда
  echo 'больше чем одна строка'; 
еще 
  echo 'одиночная или нулевая строка'; 
фи
Ханну
источник
0

Небольшое изменение этого кода должно сделать это. Вы можете поместить его в свой собственный скрипт для повторного использования следующим образом:

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

Затем вы можете использовать его так (при условии, что вы назвали предыдущий скрипт 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
источник
Я получаю синтаксическую ошибку на первом fi. К сожалению, я застрял на Bash 3.1 (версия msysgit). Я не вижу ничего похожего на синтаксическую ошибку, но, очевидно, что-то упускаю. Мысли?
jpmc26
@ jpmc26 Там была ошибка. Я обновил его, чтобы он стал внешним скриптом, чтобы его было проще использовать.
Кроу
@ jpmc26 Я добавил еще несколько проверок для проверки других нечетных входных данных.
Кроу
0

Игнорирование висячих пустых строк

Вот подход, использующий awk:

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

Как это работает:

  • echo "$ TEST"

    Это берет любую переменную оболочки, которая нас интересует, и отправляет ее в стандарт.

  • tac

    Это меняет порядок строк так, что последняя строка возвращается первой. После выполнения tacзавершающие строки становятся ведущими.

    (Название tacявляется обратным catпо той причине, что tacделает то, что catделает, но в обратном порядке.)

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

    Это сохраняет номер строки первой непустой строки в переменной f. После прочтения во всех строках он сравнивается fс общим количеством строк NR. если fравно NR, то у нас была только одна строка (игнорируя начальные пробелы), и мы завершаем работу с кодом 0. Если после первой пустой строки была одна или несколько строк, то она завершается с кодом `.

  • && echo "Found A Single Line"

    Если awkвыйти с кодом 0, то echoоператор выполняется.

Игнорирование как начальных, так и конечных пустых строк

Создав одну дополнительную awkпеременную, мы можем расширить тест, чтобы игнорировать как начальные, так и конечные пустые строки:

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

Поскольку эта версия awkкода обрабатывает как начальные, так и конечные пробелы, tacбольше не нужна.

Взяв awkкод по частям:

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

    Если переменная firstравна нулю (или она еще не установлена), и в строке есть символ, любой символ, тогда устанавливается firstномер строки. Когда awkзакончится чтение строк, firstбудет установлен номер строки первой непустой строки.

  • /./ {last=NR}

    Если в строке есть какой-либо символ, установите для переменной lastномер текущей строки. Когда awkчтение всех строк завершено, эта переменная будет иметь номер последней непустой строки.

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

    Это выполняется после того, как все строки были прочитаны. Если firstравно last, то мы увидели ноль или строку непустых строк и awkвыходов с кодом 0. В противном случае он завершается с кодом 1. Сценарий оболочки может тестировать код выхода как обычно с помощью ifоператоров или &&или ||.

John1024
источник