我想检查一个字符串是否以“节点”开始,例如。“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)。

其他回答

你可以选择你想要检查的字符串部分:

if [ "${HOST:0:4}" = user ]

对于你接下来的问题,你可以使用OR:

if [[ "$HOST" == user1 || "$HOST" == node* ]]

如果您正在使用最新版本的Bash (v3+),我建议使用Bash正则表达式比较运算符=~,例如,

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

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

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

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

User *表示使用和零次或多次出现r,因此使用和userrrr将匹配。 用户。*表示用户和零或多次出现任何字符,因此user1, userX将匹配。 ^用户。*表示匹配模式用户。*在$HOST的开头。

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

请注意,Bash =~操作符仅在右侧为unquote时进行正则表达式匹配。如果你在右边引用,“模式的任何部分都可以被引用,以迫使它作为字符串进行匹配。”即使在进行参数展开时,也不应该在右边引用。

在Mark Rushakoff的最高级别答案中添加了更多的语法细节。

表达式

$HOST == node*

也可以写成

$HOST == "node"*

效果是一样的。只要确保通配符在引用的文本之外。如果通配符在引号内,它将按字面解释(即不是通配符)。

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

我总是尝试坚持使用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,所以我们必须使用字符串。但是用字符串嵌套函数调用是不可能的,管道是不可能的,等等。)