以下bash语法验证param是否不为空:

 [[ !  -z  $param  ]]


例如:

param=""
[[ !  -z  $param  ]] && echo "I am not zero"




但是如果param为空(除了一个(或多个)空格字符),则大小写不同:

param=" " # one space
[[ !  -z  $param  ]] && echo "I am not zero"


输出“我不是零”。

如何更改测试以将仅包含空格字符的变量视为空?

评论

根据人工测试:-z STRING-STRING的长度为零。如果要删除$ param中的所有空格,请使用$ {param // /}

哇,根本没有任何* nix内置的简单trim()函数吗?如此众多的黑客实现了如此简单的目标...

@ADTC $(sed's / ^ \ s + | \ s + $ // g'<<< $ string)对我来说似乎很简单。为什么要重新发明轮子?

因为它可能更漂亮

只是注意[[! -z $ param]]等效于test! -z $ param。

#1 楼

首先,请注意-z测试明确用于:


字符串的长度为零


,即,仅包含空格的字符串应在-z下不是正确的,因为它的长度非零。

您想要的是使用模式替换参数扩展从变量中删除空格:

[[ -z "${param// }" ]]


这将扩展param变量,并用空字符替换模式的所有匹配项(单个空格),因此仅包含空格的字符串将被扩展为空字符串。


工作原理的本质是${var/pattern/string}pattern的第一个最长匹配替换为string。当pattern/(如上所述)开头时,它将替换所有匹配项。由于替换为空,因此我们可以省略最终的/string值:


$ {parameter / pattern / string}

模式被扩展为产生与文件名扩展中一样的模式。扩展参数,并将模式与其值的最长匹配项替换为字符串。如果模式以“ /”开头,则所有匹配的模式都将替换为字符串。通常只替换第一个比赛。 ...如果string为null,则删除模式匹配项,并且/后面的模式可以省略。


所有这些之后,我们以${param// }删除所有空格。

请注意,尽管kshzsh(起源于此),bashsh中都存在该语法,但它不是POSIX,因此不应在q4312079q脚本中使用。

评论


使用他们说的sed ...只需回显他们说的变量...

–mikezter
17年5月15日23:57

嗯如果它是$ {var / pattern / string},那么不应该是[[-z $ {param / /}]]],并且在斜杠之间将空格作为模式,而在字符串之后什么也没有?

–杰西·奇斯霍尔姆(Jesse Chisholm)
17年5月22日在17:51

@JesseChisholm“因为替换为空,所以我们可以省略最后的/和字符串值”; “如果字符串为null,则将删除模式匹配项,并且可以省略/以下模式。”

–迈克尔·荷马
17年5月22日在19:21

@MichaelHomer答案[[-z“ $ {param //}”]]肯定看起来像模式是空的,替换字符串是单个空格。啊!如果图案以斜杠开头,我现在就可以看到它,而我错过了该部分。因此模式为/,并且字符串保留为空,因此为空。谢谢。

–杰西·奇斯霍尔姆(Jesse Chisholm)
17年9月9日在0:59



bash注意:如果在set -o名词集合(set -u)中运行,并且未设置param(而不是null或空格),则将生成未绑定的变量错误。 (set + u; .....)将免除此测试。

–布赖恩·克里斯曼(Brian Chrisman)
17年12月8日在7:11



#2 楼

检查字符串仅包含授权集中的字符的简单方法是测试是否存在未授权字符。因此,不是测试字符串是否仅包含空格,而是测试字符串是否包含除空格之外的某些字符。在bash,ksh或zsh中:

if [[ $param = *[!\ ]* ]]; then
  echo "$param contains characters other than space"
else
  echo "$param consists of spaces only"
fi


“仅包含空格”包括空(或未设置)变量的情况。

您可能需要测试任何空白字符。使用[[ $param = *[^[:space:]]* ]]使用语言环境设置,或您要测试的任何空白字符的显式列表,例如[[ $param = *[$' \t\n']* ]]用于测试空格,制表符或换行符。

将字符串与=内的带有[[ … ]]的模式匹配是ksh扩展名(也存在于bash和zsh中)。在任何Bourne / POSIX风格中,都可以使用case构造将字符串与模式进行匹配。请注意,标准外壳模式使用!来取消字符集,而不是像大多数正则表达式语法那样使用^

case "$param" in
  *[!\ ]*) echo "$param contains characters other than space";;
  *) echo "$param consists of spaces only";;
esac


要测试空白字符,请使用$'…'语法特定于ksh / bash / zsh;您可以按原样在脚本中插入这些字符(请注意,换行符必须在引号内,因为反斜杠+换行符将扩展为空),或生成它们,例如

whitespace=$(printf '\n\t ')
case "$param" in
  *[!$whitespace]*) echo "$param contains non-whitespace characters";;
  *) echo "$param consists of whitespace only";;
esac


评论


这几乎非常好-但是,到目前为止,它还没有回答所问的问题。它当前可以告诉您未设置或为空的shell变量与仅包含空格的变量之间的区别。如果您接受我的建议,则将添加尚未通过其他任何明确测试外壳变量设置的答案来转换的参数扩展形式-我的意思是$ {var?not set}-通过该测试并存活下来将确保该变量例如,与您的*)大小写匹配将产生确定的答案。

–mikeserv
2014年7月29日在2:06



更正-实际上,它可以回答最初提出的问题,但此后对其进行了编辑,从根本上改变了问题的含义,因此使您的回答无效。

–mikeserv
2014年7月29日4:09

您需要在mksh中使用[[$ param = * [!\] *]]。

–StéphaneChazelas
2014年7月30日在6:01

#3 楼

POSIXly:

case $var in
  (*[![:blank:]]*) echo '$var contains non blank';;
  (*) echo '$var contains only blanks or is empty or unset'
esac


区分空白,非空白,空,未设置:

case ${var+x$var} in
  (x) echo empty;;
  ("") echo unset;;
  (x*[![:blank:]]*) echo non-blank;;
  (*) echo blank
esac


[:blank:]用于水平间距字符(ASCII中的空格和制表符,但您的语言环境中可能还有更多;某些系统将包含不间断空格(如果可用),有些则不会)。如果还需要垂直间距字符(例如换行符或换页符),请用[:blank:]替换[:space:]

评论


POSIXly是理想的,因为它可以与(可能更好)的破折号一起使用。

–肯·夏普
2015年12月4日13:52

zsh似乎与[![:blank:]]有问题,它引发:b是无效的修饰符。在sh和ksh仿真中,它引发了[

–cuonglm
16年1月21日在16:03



@cuonglm,您尝试了什么? var = foo zsh -c'case $ {var + x $ var} in(x * [![:blank:]] *)echo x; esac'对我来说还可以。未找到的事件仅适用于交互式外壳。

–StéphaneChazelas
16年1月21日在16:27

@StéphaneChazelas:嗯,对,我尝试使用交互式shell。 :b无效修饰符有点奇怪。

–cuonglm
16年1月21日在16:53

@FranklinYu,在OS / X上,sh是使用--enable-xpg-echo-default和--enable-strict-posix-default构建的bash,以便与Unix兼容(这涉及回显'\ t'输出选项卡)。

–StéphaneChazelas
16年8月9日在20:20

#4 楼

编写shell脚本而不是使用良好的脚本语言编写脚本的唯一剩余原因是,极端的可移植性是否是首要考虑的问题。可以肯定的是,旧有的/bin/sh是唯一的东西,但是例如Perl比Bash更可能跨平台使用。因此,切勿编写使用并非真正通用的功能的Shell脚本-切记,一些专有的Unix供应商在POSIX.1-2001之前冻结了其Shell环境。

进行此测试的方法,但必须使用tr

[ "x`printf '%s' "$var" | tr -d "$IFS"`" = x ]


$IFS的默认值通常是空格,制表符和换行符。 )

(内置的printf本身可以随身携带,但是依靠它比找出echo的哪个变体麻烦得多。)

评论


这有点令人费解。测试字符串是否包含某些字符的通常可移植方式是带大小写的。

–吉尔斯'所以-不再是邪恶的'
14年7月29日在0:38

@Gilles我认为不可能写一个case glob来检测一个为空或仅包含空格字符的字符串。 (使用正则表达式很容易,但是case不能使用正则表达式。如果您关心换行符,则答案中的构造将不起作用。)

– zwol
2014年7月29日在1:27

我以空格作为示例,因为这正是问题的所在。测试空白字符同样容易:* [![:space:]] *)的case $ param…。如果要测试IFS字符,可以使用模式* [$ IFS] *。

–吉尔斯'所以-不再是邪恶的'
2014年7月29日在1:44

@mikeserv在一个非常认真的防御脚本中,您在一开始就将IFS显式设置为 ,然后再也不要碰它。我以为那会分散注意力。

– zwol
2014年7月29日14:00

关于模式中的变量,我认为这适用于所有Bourne版本和所有POSIX shell。这将需要额外的代码来检测案例模式并关闭变量扩展,我想不出这样做的理由。我的.profile中有几个实例,该实例已由许多Bourne shell执行。当然,如果IFS具有某些非默认值(空(或未设置),包含!,以!或^开头),则[$ IFS]不会执行预期的操作。

–吉尔斯'所以-不再是邪恶的'
14年7月29日在16:26

#5 楼

if [[ -n "${variable_name/[ ]*\n/}" ]]
then
    #execute if the the variable is not empty and contains non space characters
else
    #execute if the variable is empty or contains only spaces
fi


评论


这摆脱了任何空格字符,而不仅仅是一个空格,对吗?谢谢

–亚历山大·米尔斯(Alexander Mills)
16 Dec 11'在1:02

#6 楼

要测试变量是否为空或包含空格,您还可以使用以下代码:

${name:?variable is empty}


评论


我认为您的答案被否决了,因为“或包含空格”是不正确的。

–伯恩哈德
2014年7月29日在11:19

小心-这会杀死当前的shell。最好放在(:$ {subshel​​l?})中。另外-这将写入stderr-您可能需要重定向。最重要的是,如果变量未设置为null或null,则求值为该变量的实际值。如果其中有命令,则只需运行它即可。最好在:上运行该测试。

–mikeserv
2014年7月29日在12:59

它将如何杀死外壳。您也可以测试它,首先定义name = aaaa,然后运行此命令echo $ {name:?variable is empty},它将打印变量名称的值,然后运行此命令echo $ {name1:?variable is empty},它将打印-sh:name1:变量为空

– Pratik
14年7月29日在16:24

是的-echo $ {name:?variable is empty}将评估为$ name的非null值,否则将终止shell。因此,出于相同的原因,您也不会提示符> $ randomvar,您也不必$ {var?}-如果其中有一个命令,它可能会运行-而且您也不知道它是什么。交互式外壳程序不必退出-这就是为什么您不需要这样做。不过,如果您想查看一些测试,这里有很多测试。.这个测试时间不长...

–mikeserv
2014年7月30日在2:31



#7 楼

如果参数未设置/未定义或为空(在bash,ksh和zsh中),则您发布的代码[[ ! -z $param ]] && echo "I am not zero"将输出I am not zero。更大范围的外壳):

 [   -z "${param#"${param%%[! ]*}"}"   ] && echo "empty"


说明:


${param# … }删除了前导文字。
那前导文本由以下内容给出:${param%%[! ]*}

哪个扩展到所有非空格字符之前的所有空格,即所有前导空格。

整个扩展的最终结果是:

如果长度为0,则测试此扩展结果。


如果结果为空,则变量为空,或者
删除前导空格使其为空。

因此,如果测试为true,则该变量要么为空,要么内部只有空格。


这个概念很容易扩展到更多的字符类型。要同时包含制表符,请在方括号表达式内放置一个明确的制表符:

 [ -z "${param#"${param%%[!     ]*}"}" ] && echo "empty"


,或使用带有需要删除的字符的变量:

 var=$' \t'                                    # in ksh, bash, zsh
 [ -z "${param#"${param%%[!$var]*}"}" ] && echo "empty"


,或者您可以使用一些POSIX“字符类表达式”(空白表示空格和制表符):

 [ -z "${param#"${param%%[![:blank:]]*}"}" ] && echo "empty"


#8 楼

要检查变量是否只有空格(包括多行变量),请尝试以下操作:

[[ $var = *[$" \t\n"]* ]]


或使用xargs:

[[ -z $(echo $var | xargs) ]]


或使用sed:

[[ -z $(sed "/^$/d" <<< $var) ]]


#9 楼

试试这个:

$ [[ -z \`echo $n\` ]] && echo zero

zero