Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/string/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
String 在Bash中,如何检查字符串是否以某个值开头?_String_Bash_Comparison - Fatal编程技术网

String 在Bash中,如何检查字符串是否以某个值开头?

String 在Bash中,如何检查字符串是否以某个值开头?,string,bash,comparison,String,Bash,Comparison,我想检查字符串是否以“node”开头,例如“node001”。差不多 if [ $HOST == user* ] then echo yes fi 我怎样才能正确地做呢 我还需要组合表达式来检查主机是“user1”还是以“node”开头 如何正确执行此操作?您可以仅选择要检查的字符串部分: if [ "${HOST:0:4}" = user ] 对于后续问题,您可以使用: 如果您使用的是最新版本的Bash(v3+),我建议使用Bash regex比较运算符=~,例如 if [[ "

我想检查字符串是否以“node”开头,例如“node001”。差不多

if [ $HOST == user* ]
  then
  echo yes
fi
我怎样才能正确地做呢


我还需要组合表达式来检查主机是“user1”还是以“node”开头


如何正确执行此操作?

您可以仅选择要检查的字符串部分:

if [ "${HOST:0:4}" = user ]
对于后续问题,您可以使用:


如果您使用的是最新版本的Bash(v3+),我建议使用Bash regex比较运算符
=~
,例如

if [[ "$HOST" =~ ^user.* ]]; then
    echo "yes"
fi
if [[ "$HOST" =~ ^user.*|^host1 ]]; then
    echo "yes"
fi

要匹配正则表达式中的
这个或那个
,请使用
|
,例如

if [[ "$HOST" =~ ^user.* ]]; then
    echo "yes"
fi
if [[ "$HOST" =~ ^user.*|^host1 ]]; then
    echo "yes"
fi
注意-这是“正确的”正则表达式语法

  • user*
    表示
    use
    和零次或多次出现的
    r
    ,因此
    use
    userrrr
    将匹配
  • user.*
    表示
    user
    和任何字符的零次或多次出现,因此
    user1
    userX
    将匹配
  • ^user.*
    表示匹配$HOST开头的模式
    user.*
如果您不熟悉正则表达式语法,请尝试参考。

上的这段代码说明:

所以你说的几乎是对的;你需要双括号,而不是单括号


关于你的第二个问题,你可以这样写:

HOST=user1
if  [[ $HOST == user1 ]] || [[ $HOST == node* ]] ;
then
    echo yes1
fi

HOST=node001
if [[ $HOST == user1 ]] || [[ $HOST == node* ]] ;
then
    echo yes2
fi
这会引起共鸣

yes1
yes2

Bash的
if
语法很难适应(IMO)。

我更喜欢已经发布的其他方法,但有些人喜欢使用:

case "$HOST" in 
    user1|node*) 
            echo "yes";;
        *)
            echo "no";;
esac
编辑:

我已将您的备选方案添加到上述案例陈述中

在编辑的版本中,括号太多。应该是这样的:

if [[ $HOST == user1 || $HOST == node* ]];
$ if yesNo "asfd"; then echo "true"; else echo "false"; fi

asfd [Y/n] y
true

$ if yesNo "asfd"; then echo "true"; else echo "false"; fi

asfd [Y/n] Y
true

$ if yesNo "asfd"; then echo "true"; else echo "false"; fi

asfd [Y/n] yes
true

$ if yesNo "asfd"; then echo "true"; else echo "false"; fi

asfd [Y/n]
true

$ if yesNo "asfd"; then echo "true"; else echo "false"; fi

asfd [Y/n] n
false

$ if yesNo "asfd"; then echo "true"; else echo "false"; fi

asfd [Y/n] ddddd
false
$ if yesNo "asfd" n; then echo "true"; else echo "false"; fi

asfd [y/N]
false

$ if yesNo "asfd" n; then echo "true"; else echo "false"; fi

asfd [y/N] y
true

$ if yesNo "asfd" y; then echo "true"; else echo "false"; fi

asfd [Y/n] n
false
不起作用,因为所有
[
[[
test
都识别相同的非递归语法。请参阅Bash手册页上的“条件表达式”一节

另一方面,SUSv3说

KornShell派生的条件命令(双括号[[]])在早期的提案中已从shell命令语言描述中删除。有人提出异议,认为真正的问题是误用测试命令([),并将其放入shell是解决问题的错误方法。相反,适当的文档和新的shell保留字()就足够了

需要多个测试操作的测试可以在shell级别通过单独调用test命令和shell逻辑来完成,而不是使用test的易出错-o标志

您需要这样编写,但test不支持:

if [ $HOST == user1 -o $HOST == node* ];
then
echo yes
fi
测试使用=表示字符串相等,更重要的是,它不支持模式匹配

case
/
esac
对模式匹配有很好的支持:

case $HOST in
user1|node*) echo yes ;;
esac
它还有一个额外的好处,即它不依赖于Bash,并且语法是可移植的


@OP,对于这两个问题,您可以使用case/esac:

string="node001"
case "$string" in
  node*) echo "found";;
  * ) echo "no node";;
esac
第二个问题

case "$HOST" in
 node*) echo "ok";;
 user) echo "ok";;
esac

case "$HOST" in
 node*|user) echo "ok";;
esac
还是bash4.0


我总是坚持使用POSIX
sh
,而不是使用Bash扩展,因为脚本的一个要点是可移植性(除了连接程序,而不是替换它们)

sh
中,有一种简单的方法可以检查“is prefix”条件

case $HOST in node*)
    # Your code here
esac
考虑到sh的年代久远、晦涩难懂(Bash并不是解药:它更复杂、更不一致、更不可移植),我想指出一个非常好的功能方面:虽然一些语法元素(如
case
)是内置的,但生成的构造与任何其他作业都没有什么不同。它们可以以相同的方式组成:

if case $HOST in node*) true;; *) false;; esac; then
    # Your code here
fi
甚至更短

if case $HOST in node*) ;; *) false;; esac; then
    # Your code here
fi
甚至更短(只是将
作为一种语言元素呈现——但现在这种风格很糟糕)

如果您喜欢显式,请构建您自己的语言元素:

beginswith() { case $2 in "$1"*) true;; *) false;; esac; }
这不是很好吗

if beginswith node "$HOST"; then
    # Your code here
fi
由于
sh
基本上只是作业和字符串列表(以及内部进程,作业由这些进程组成),我们现在甚至可以进行一些简单的函数编程:

beginswith() { case $2 in "$1"*) true;; *) false;; esac; }
checkresult() { if [ $? = 0 ]; then echo TRUE; else echo FALSE; fi; }

all() {
    test=$1; shift
    for i in "$@"; do
        $test "$i" || return
    done
}

all "beginswith x" x xy xyz ; checkresult  # Prints TRUE
all "beginswith x" x xy abc ; checkresult  # Prints FALSE
这很优雅。我并不主张在任何严肃的事情上使用
sh
——它在现实世界中的要求上太快就被打破了(没有lambdas,所以我们必须使用字符串。但是用字符串嵌套函数调用是不可能的,管道是不可能的,等等)由于
#
在Bash中有意义,因此我得到了以下解决方案

此外,我更喜欢用“”填充字符串以克服空格等

A="#sdfs"
if [[ "$A" == "#"* ]];then
    echo "Skip comment line"
fi

虽然我发现这里的大多数答案都是正确的,但其中许多都包含了不必要的羞怯。这为您提供了所需的一切:

[ "${host#user}" != "${host}" ]

${var#expr}
${var}
中去掉匹配
expr
的最小前缀,并返回该前缀。因此,如果
${host}
用户开始(
节点
),则
${host#用户
${host}节点
)与
相同


expr
允许使用通配符,因此
${host#node???}
和friends也可以使用。

添加一点语法细节来标记Rushakoff的最高级别答案

表情

$HOST == node*
也可以写成

$HOST == "node"*

效果是一样的。只需确保通配符在引号内。如果通配符在引号内,它将被逐字解释(即不是通配符)。

我调整了@markrushakoff的答案,使其成为可调用函数:

function yesNo {
  # Prompts user with $1, returns true if response starts with y or Y or is empty string
  read -e -p "
$1 [Y/n] " YN

  [[ "$YN" == y* || "$YN" == Y* || "$YN" == "" ]]
}
像这样使用它:

if [[ $HOST == user1 || $HOST == node* ]];
$ if yesNo "asfd"; then echo "true"; else echo "false"; fi

asfd [Y/n] y
true

$ if yesNo "asfd"; then echo "true"; else echo "false"; fi

asfd [Y/n] Y
true

$ if yesNo "asfd"; then echo "true"; else echo "false"; fi

asfd [Y/n] yes
true

$ if yesNo "asfd"; then echo "true"; else echo "false"; fi

asfd [Y/n]
true

$ if yesNo "asfd"; then echo "true"; else echo "false"; fi

asfd [Y/n] n
false

$ if yesNo "asfd"; then echo "true"; else echo "false"; fi

asfd [Y/n] ddddd
false
$ if yesNo "asfd" n; then echo "true"; else echo "false"; fi

asfd [y/N]
false

$ if yesNo "asfd" n; then echo "true"; else echo "false"; fi

asfd [y/N] y
true

$ if yesNo "asfd" y; then echo "true"; else echo "false"; fi

asfd [Y/n] n
false
以下是提供指定默认值的更复杂版本:

function toLowerCase {
  echo "$1" | tr '[:upper:]' '[:lower:]'
}

function yesNo {
  # $1: user prompt
  # $2: default value (assumed to be Y if not specified)
  # Prompts user with $1, using default value of $2, returns true if response starts with y or Y or is empty string

  local DEFAULT=yes
  if [ "$2" ]; then local DEFAULT="$( toLowerCase "$2" )"; fi
  if [[ "$DEFAULT" == y* ]]; then
    local PROMPT="[Y/n]"
  else
    local PROMPT="[y/N]"
  fi
  read -e -p "
$1 $PROMPT " YN

  YN="$( toLowerCase "$YN" )"
  { [ "$YN" == "" ] && [[ "$PROMPT" = *Y* ]]; } || [[ "$YN" = y* ]]
}
像这样使用它:

if [[ $HOST == user1 || $HOST == node* ]];
$ if yesNo "asfd"; then echo "true"; else echo "false"; fi

asfd [Y/n] y
true

$ if yesNo "asfd"; then echo "true"; else echo "false"; fi

asfd [Y/n] Y
true

$ if yesNo "asfd"; then echo "true"; else echo "false"; fi

asfd [Y/n] yes
true

$ if yesNo "asfd"; then echo "true"; else echo "false"; fi

asfd [Y/n]
true

$ if yesNo "asfd"; then echo "true"; else echo "false"; fi

asfd [Y/n] n
false

$ if yesNo "asfd"; then echo "true"; else echo "false"; fi

asfd [Y/n] ddddd
false
$ if yesNo "asfd" n; then echo "true"; else echo "false"; fi

asfd [y/N]
false

$ if yesNo "asfd" n; then echo "true"; else echo "false"; fi

asfd [y/N] y
true

$ if yesNo "asfd" y; then echo "true"; else echo "false"; fi

asfd [Y/n] n
false

grep

忘记性能,这是POSIX,看起来比
case
解决方案更好:

mystr="abcd"
if printf '%s' "$mystr" | grep -Eq '^ab'; then
  echo matches
fi
说明:

  • printf“%s”
    要防止
    printf
    展开反斜杠转义:
  • grep-q<