Як перевірити, чи змінна має декілька непорожніх рядків у 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.

Що стосується мого конкретного випадку, я не думаю, що мені потрібно турбуватися про провідні рядки, але не завадило б знати, як це зробити.

Як я можу це зробити?



@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

Вищезгадане ігнорує всі порожні рядки: провідні, кінцеві та внутрішні. Але зауважте, що внутрішня порожня лінія неможлива, якщо немає принаймні двох непорожніх ліній, тому її існування не може змінити питання про те, чи є більше одного рядка після обрізки провідних та кінцевих рядків.


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

Див. Https://stackoverflow.com/questions/16414410/delete-empty-lines-using-sed,
щоб дізнатися, як обрізати / видалити пробіли та порожні рядки за допомогою sed.

Тепер напишіть ваше if expression ...використання $( ... )всередині лапок, щоб отримати кількість рядків, і протестуйте на число:

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

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

Я отримую помилку синтаксису на першому fi. На жаль, я застряг на bash 3.1 (версія msysgit). Я не бачу нічого, що мені схоже на синтаксичну помилку, але явно чогось мені не вистачає. Думки?
jpmc26

@ jpmc26 У нього була помилка. Я оновив його на зовнішній скрипт, щоб було простіше і його використовувати.
krowe

@ jpmc26 Я додав ще кілька перевірок, щоб перевірити інший непарний вхід.
krowe

0

Ігнорування проміжних порожніх рядків

Ось підхід із використанням awk:

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

Як це працює:

  • відлуння "$ 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операторами або &&або ||.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.