如何在 bash 中测试一个变量是否有多个非空行?

如何在 bash 中测试一个变量是否有多个非空行?

假设我在 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

就我的具体情况而言,我认为我不需要担心前导空行,但知道如何做到这一点也不会有什么坏处。

我怎样才能做到这一点?

答案1

我知道的最简单的解决方案是:

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

上述代码忽略了所有空白行:前导、尾随和内部。但请注意,除非至少有两条非空白行,否则不可能有内部空白行,因此它的存在无法改变在修剪前导和尾随空白行后是否有多行的问题。

答案2

$ 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 ...用途 $( ... )以获取行数,并根据该数字进行测试:

如果 [ "$(echo "$MULTILINE" | sed -re '/^$/d' | wc -l)" -gt 1 ]; 然后
  echo ‘多行’;
别的
  回显‘单线或无线’;

答案3

稍作修改此代码应该可以。您可以将其放入自己的脚本中以供重复使用,如下所示:

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

答案4

忽略尾随的空行

以下是使用的方法awk

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

怎么运行的:

  • 回显“$TEST”

    这将获取我们感兴趣的任何 shell 变量并将其发送到标准输出。

  • 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。否则,它将退出并显示代码。shell 脚本可以像往常一样使用语句或或来1测试退出代码。if&&||

相关内容