在Bash中测试字符串是否包含非空格字符

24
我的脚本正在读取和显示ID3标签。我正在尝试在字段为空时将其输出为"unknown",但是我尝试的每个if语句都无法工作。ID3标签具有固定大小,因此它们永远不会为空,但是如果没有值,则填充了空格。例如,标题标签长度为30个字符。到目前为止,我尝试过以下内容: echo :$string: #在2个冒号之间输出空格: if [ -z "$string" ] #由于有空格,该代码将始终求值为true: x=echo $string | tr -d ' '; if [ -z "$string" ]; #仍然求值为true,但输出:$x:它输出了两个冒号: 脚本
#!bin/bash
echo "$# files";
while [ "$i" != "" ];
do
   TAG=`tail -c 128 "$i" | head -c 3`;
   if [ $TAG="TAG" ]
   then
      ID3[0]=`tail -c 125 "$1" | head -c 30`;
      ID3[1]=`tail -c 95 "$1" | head -c 30`;
      ID3[2]=`tail -c 65 "$1" | head -c 30`;
      ID3[3]=`tail -c 35 "$1" | head 4`;
      ID3[4]=`tail -c 31 "$i" | head -c 28`;
      for i in "${ID3[@]}"
      do
         if [ "$(echo $i)" ] #the if statement mentioned
         then
            echo "N/A";
         else
            echo ":$i:";
         fi
      done
   else
      echo "$i does not have a proper id3 tag";
   fi
   shift;
done

Michal Politowski:-z 表示操作数长度为零。 - Peter.O
@Peter.O:是的,$x 是应该被测试的字符串,而不是 $string。 - ams
是的,我之前在上传脚本之前使用$string作为示例;$i是来自数组的值。我的循环可能有问题吗? - Yamiko
你还需要将 if [ $TAG="TAG" ] 改为 if [ "$TAG" = "TAG" ] -- 第一个版本只发送单个非空参数到 [ 命令,因此它总是返回 true。 - glenn jackman
@yamikoWebs 除了 glenn jackman 的评论之外,你混淆了 $1$i,以及 head 4 (?) head -c 4 … 经过这些问题的修复和你在 if 语句方面的选择,脚本工作得很好 :) - Peter.O
http://unix.stackexchange.com/questions/146942/how-can-i-test-if-a-variable-is-empty-or-contains-only-spaces - Ciro Santilli OurBigBook.com
8个回答

38

很多答案比它们应该的要复杂或难以阅读。

[[ $string = *[[:space:]]* ]]  && echo "String contains whitespace"
[[ $string = *[![:space:]]* ]] && echo "String contains non-whitespace"

1
这并没有回答问题。原帖的问题是如何测试一个字符串是否至少包含一个非空格字符。而这个测试是用来测试一个字符串至少包含一个空格字符的。 - kkm
1
@kkm,很尴尬这个错误存在了这么长时间。已经解决。 - Charles Duffy
@CharlesDuffy:谢谢!我不知道!模式否定。很酷的Bash技巧! - kkm
@kkm,这不是一个 bashism -- 这是 POSIX fnmatch 行为,因此它适用于标准兼容的 shell globbing 表达式。请参阅 http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_13_01 - Charles Duffy
不过,是的,[[ ]]当然是bashism(嗯,它本身是一个被窃取/采用的ksh-ism)。 :) - Charles Duffy
显示剩余4条评论

8
你可以使用bash的正则表达式语法。
需要使用双方括号[[ ... ]],(通常更加灵活)。
变量本身不需要加引号。正则表达式本身不能加引号。
for str in "         "  "abc      " "" ;do
    if [[ $str =~ ^\ +$ ]] ;then 
      echo -e "Has length, and contain only whitespace  \"$str\"" 
    else 
      echo -e "Is either null or contain non-whitespace \"$str\" "
    fi
done

输出

Has length, and contain only whitespace  "         "
Is either null or contain non-whitespace "abc      " 
Is either null or contain non-whitespace "" 

所有的空格都在回显中。 - Yamiko
感谢yamikoWebs...我一开始使用正则表达式,然后选择了globbing...现在我又回到了正则表达式...编辑答案以使用bash的正则表达式。 - Peter.O
1
目前的代码仅检查空格,未考虑所有空白字符——例如它没有处理制表符、换行符等。 - Charles Duffy
此外,echo -e 在这里几乎肯定是错误的 -- 如果您想显示不可打印的字符并将转义序列文字化,则更适合此工作的工具可能是:printf 'Has length, and contains only whitespace: "%q"\n' "$str" - Charles Duffy
但是使用 echo -e 意味着你正在将转义序列渲染为它们所代表的字面字符,这使得显示给用户处理的数据变得更加远离实际数据,而不是更接近它(如果数据包含一个字面上的反斜杠后跟一个 n,为什么他们想要看到它与字面意义上的换行符不可区分的方式呢?) - Charles Duffy

3
[[ -z `echo $string` ]]

反引号执行其中的命令;bash行解析将制表符和换行符转换为空格,并连接双空格。echo命令重新发出此字符串,该字符串通过[[ ]]缩小为一个空字符串进行最终测试。我认为这是通过以下测试的最短解决方案:

> VAR="$(echo -e " \n\t")"
> [[ -z  `echo $VAR` ]] ; echo $?
0
> VAR="$(echo -e " \na\t")"
> [[ -z  `echo $VAR` ]] ; echo $?
1
> VAR="$(echo -e "aaa bbb")"
> [[ -z  `echo $VAR` ]] ; echo $?
1
> VAR=
> [[ -z  `echo $VAR` ]] ; echo $?
0

3
一种非特定于bash的仅限于shell的变体:
case "$string" in
 *[!\ ]*) echo "known";;
 *) echo "unknown";;
esac

4
最好使用POSIX字符类[[:space:]],而不是具体列举\ - Charles Duffy

1
启用扩展的通配符(shopt -s extglob):
if [ -n "${string##+([[:space:]])}" ]; then
    echo '$string has non-whitespace characters'
fi

输出了太多的参数并且需要二进制运算符。 - Yamiko
它们都在回显,包括那些我怀疑有空格的。有没有一种方法可以验证它们是空格而不是其他东西? - Yamiko

0
if [ "$(echo "$string" | tr -s ' ')" == " " ]; then
  echo "all white space"
fi

这将所有重复的空格压缩成一个空格,并进行比较。


我正在循环遍历所有的标签,但并不是所有的标签都有30个字符,是否有其他方法来测试一个字符串是否全为空格? - Yamiko
标签中的单词之间会有空格吗? - ams
你的例子对我来说始终是为 false 的。 - Yamiko
好的,我以为我已经测试过了。你的输入是什么,确切地说? - ams
在测试时,我将字符串封装在::中以查看被回显的内容。 - Yamiko
显示剩余3条评论

0

这个检查零长度或空格或制表符

S="Something"
if [[ "x$S" == "x" || "x$S" == x*\ * || "x$S" == x*\    * ]] ;then
  echo "Is not OK"
else
  echo "Is OK"
fi

0
分享一种更便携的方法,不需要使用双方括号 [[ ]],并尽可能保持简单。
检测一个仅包含空格或 = null 的字符串:
if [ -z "${string// }" ]; then <do something>; fi

在这种情况下,它将是:
${var// }

例如:

if [ -z "${string// }" ]; then echo "It's empty!"; fi

这个程序的作用是通过替换将所有的空格变成null。如果$string只包含空格,则-z测试将评估为TRUE。如果字符串中有非空格字符,则方程式将评估为FALSE。

进一步阐述BASH(因为OP在BASH中提出了这个问题),上面的例子不会捕获制表符,但是可以做到。以下是更多在BASH中预期工作和不工作的示例。

假设搜索字符串中有一个制表符。

这个可以工作:

string=$(echo -e "\t"); if [ -z ${string// } ]; then echo "It's empty!"; fi

但是这些不行:

string=$(echo -e "\t"); if [ -z "${string// }" ]; then echo "It's empty!"; fi
string=$(echo -e "\t"); if [ -z '${string// }' ]; then echo "It's empty!"; fi

以上两个示例都报告字符串不为空。如果您认为制表符是空格,那么这将是一个问题,并且您需要使用第一个示例。

那么换行符呢?让我们看一下\n的情况。首先,“正确”的行为取决于您的期望。

这些将换行符(\n)视为空格(方程式计算为TRUE):

string=$(echo -e "\n\n"); if [ -z ${string// } ]; then echo "It's empty!"; fi
string=$(echo -e "\n\n"); if [ -z "${string// }" ]; then echo "It's empty!"; fi

这个方程的值为FALSE,意味着这个方程认为换行符不是空格。

string=$(echo -e "\n\n"); if [ -z '${string// }' ]; then echo "It's empty!"; fi

如果您需要检查换行符、制表符和空格,您可能需要使用两个IF/THEN语句或上面描述的CASE方法。


这个有效,${var// } 到底代表什么?它是在替换某些东西吗? - user5047085
是的。它将null替换为空格字符(也称为空格)。 - MrPotatoHead

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接