9

Скажем, у меня есть две переменные в 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 .

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

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

4 ответа4

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

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

3
$ 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

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

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

if [ "$(echo "$MULTILINE" | sed -re '/^$/d' | wc -l)" -gt 1 ]; then 
  echo 'more than one line'; 
else 
  echo 'single or no line'; 
fi
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
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 или && или || ,

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .