协慌网

登录 贡献 社区

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

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

if [ $HOST == user* ]
  then
  echo yes
fi

如何正确执行?


我还需要结合表达式来检查 HOST 是 “user1” 还是以 “node” 开头

if [ [[ $HOST == user1 ]] -o [[ $HOST == node* ]] ];
then
echo yes
fi

> > > -bash: [: too many arguments

如何正确执行?

答案

《高级 Bash 脚本指南》中的此代码段说:

# The == comparison operator behaves differently within a double-brackets
# test than within single brackets.

[[ $a == z* ]]   # True if $a starts with a "z" (wildcard matching).
[[ $a == "z*" ]] # True if $a is equal to z* (literal matching).

所以你几乎正确了;您需要括号,而不是单括号。


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

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)。

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

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

要匹配正则表达式this or that | , 例如,

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

注意 - 这是 “正确” 的正则表达式语法。

  • user*表示r use和零个或多个出现,因此useuserrrr将匹配。
  • user.*表示user和任何字符的零个或多个出现,因此user1userX将匹配。
  • ^user.*表示在 $ HOST 开头匹配模式user.*

如果您不熟悉正则表达式语法,请尝试参考此资源

我始终尝试使用 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

甚至更短(仅以!但这是不好的风格)

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因为它在现实世界的要求上会很快崩溃(没有 lambda,所以我们必须使用字符串。但是不能使用字符串嵌套函数调用,不能使用管道,等等)。