如何测试变量在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谢谢,但是您可以指向其中忽略尾随空白行的特定答案吗?我没看到。(还相应地编辑了标题。)
2014年

Answers:


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

有关 如何使用sed修剪/删除空格和空白行的更多信息,请参见/programming/16414410/delete-empty-lines-using-sed

现在将您的if expression ...用法 写$( ... )在引号中以获取行数,并针对该数字进行测试:

如果[[$(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版本)。我看不到任何看起来像语法错误的东西,但是显然我缺少了一些东西。有什么想法吗?
2014年

@ 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”

    这将获取我们感兴趣的任何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使用code退出0。否则,它将以code退出1。Shell脚本可以像平常一样使用if语句或&&或测试退出代码||

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.