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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2172352/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-09 00:37:15  来源:igfitidea点击:

In Bash, how can I check if a string begins with some value?

stringbashcomparison

提问by Tim

I would like to check if a string begins with "node" e.g. "node001". Something like

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

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

How can I do it correctly?

我怎样才能正确地做到这一点?



I further need to combine expressions to check if HOST is either "user1" or begins with "node"

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

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

> > > -bash: [: too many arguments

How can I do it correctly?

我怎样才能正确地做到这一点?

回答by Mark Rushakoff

This snippet on the Advanced Bash Scripting Guidesays:

Advanced Bash Scripting Guide上的这个片段说:

# 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).

So you had it nearlycorrect; you needed doublebrackets, not single brackets.

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



With regards to your second question, you can write it this way:

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

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

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

Which will echo

哪个会回声

yes1
yes2

Bash's ifsyntax is hard to get used to (IMO).

Bash 的if语法很难习惯(IMO)。

回答by brabster

If you're using a recent version of Bash (v3+), I suggest the Bash regex comparison operator =~, for example,

如果您使用的是最新版本的 Bash (v3+),我建议您使用 Bash regex compare operator =~,例如,

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


To match this or thatin a regex, use |, for example,

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

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

Note - this is 'proper' regular expression syntax.

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

  • user*means useand zero-or-more occurrences of r, so useand userrrrwill match.
  • user.*means userand zero-or-more occurrences of any character, so user1, userXwill match.
  • ^user.*means match the pattern user.*at the begin of $HOST.
  • user*意味着use和零次或多次出现r,所以useuserrrr将匹配。
  • user.*表示user和零次或多次出现的任何字符,因此user1userX将匹配。
  • ^user.*表示匹配user.*$HOST 开头的模式。

If you're not familiar with regular expression syntax, try referring to this resource.

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

回答by Jo So

I always try to stick with POSIX shinstead of using Bash extensions, since one of the major points of scripting is portability (besides connectingprograms, not replacing them).

我总是尝试坚持使用 POSIXsh而不是使用 Bash 扩展,因为脚本编写的重点之一是可移植性(除了连接程序,而不是替换它们)。

In sh, there is an easy way to check for an "is-prefix" condition.

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

case $HOST in node*)
    # Your code here
esac

Given how old, arcane and crufty sh is (and Bash is not the cure: It's more complicated, less consistent and less portable), I'd like to point out a very nice functional aspect: While some syntax elements like caseare built-in, the resulting constructs are no different than any other job. They can be composed in the same way:

考虑到 sh 是多么古老、神秘和笨拙(而且 Bash 不是治疗方法:它更复杂、更不一致、更不便携),我想指出一个非常好的功能方面:虽然一些语法元素case是内置的,由此产生的构造与任何其他工作没有什么不同。它们可以以相同的方式组成:

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

Or even shorter

甚至更短

if case $HOST in node*) ;; *) false;; esac; then
    # Your code here
fi

Or evenshorter (just to present !as a language element -- but this is bad style now)

或者短(只是!作为一种语言元素呈现——但现在这是不好的风格)

if ! case $HOST in node*) false;; esac; then
    # Your code here
fi

If you like being explicit, build your own language element:

如果您喜欢明确表达,请构建您自己的语言元素:

beginswith() { case  in ""*) true;; *) false;; esac; }

Isn't this actually quite nice?

这真的不是很好吗?

if beginswith node "$HOST"; then
    # Your code here
fi

And since shis basically only jobs and string-lists (and internally processes, out of which jobs are composed), we can now even do some light functional programming:

由于sh基本上只有作业和字符串列表(以及由作业组成的内部进程),我们现在甚至可以进行一些轻量的函数式编程:

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

all() {
    test=; 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

This is elegant. Not that I'd advocate using shfor anything serious -- it breaks all too quickly on real world requirements (no lambdas, so we must use strings. But nesting function calls with strings is not possible, pipes are not possible, etc.)

这很优雅。并不是说我提倡将其sh用于任何严肃的事情——它在现实世界的要求上太快崩溃了(没有 lambda,所以我们必须使用字符串。但是用字符串嵌套函数调用是不可能的,管道是不可能的,等等)

回答by martin clayton

You can select just the part of the string you want to check:

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

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

For your follow-up question, you could use an OR:

对于您的后续问题,您可以使用OR

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

回答by Paused until further notice.

I prefer the other methods already posted, but some people like to use:

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

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

Edit:

编辑:

I've added your alternates to the case statement above

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

In your edited version you have too many brackets. It should look like this:

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

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

回答by dhke

While I find most answers here quite correct, many of them contain unnecessary Bashisms. POSIX parameter expansiongives you all you need:

虽然我发现这里的大多数答案都非常正确,但其中许多都包含不必要的 Bashism。POSIX 参数扩展为您提供了所需的一切:

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

and

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

${var#expr}strips the smallest prefix matching exprfrom ${var}and returns that. Hence if ${host}does notstart with user(node), ${host#user}(${host#node}) is the same as ${host}.

${var#expr}expr从中剥离最小的前缀匹配${var}并返回。因此,如果${host}没有下手usernode), (${host#user}${host#node}是一样的${host}

exprallows fnmatch()wildcards, thus ${host#node??}and friends also work.

expr允许fnmatch()通配符,因此${host#node??}和朋友也可以工作。

回答by ozma

Since #has a meaning in Bash, I got to the following solution.

由于#在 Bash 中具有意义,我得到了以下解决方案。

In addition I like better to pack strings with "" to overcome spaces, etc.

此外,我更喜欢用 "" 打包字符串以克服空格等。

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

回答by MrPotatoHead

Adding a tiny bit more syntax detail to Mark Rushakoff's highest rank answer.

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

The expression

表达方式

$HOST == node*

Can also be written as

也可以写成

$HOST == "node"*

The effect is the same. Just make sure the wildcard is outside the quoted text. If the wildcard is insidethe quotes it will be interpreted literally (i.e. not as a wildcard).

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

回答by ghostdog74

@OP, for both your questions you can use case/esac:

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

string="node001"
case "$string" in
  node*) echo "found";;
  * ) echo "no node";;
esac

Second question

第二个问题

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

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

OrBash 4.0

Bash 4.0

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

回答by just somebody

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

doesn't work, because all of [, [[, and testrecognize the same nonrecursive grammar. See section CONDITIONAL EXPRESSIONSon your Bash man page.

不起作用,因为所有[, [[, 和test识别相同的非递归语法。请参阅Bash 手册页上的条件表达式部分。

As an aside, the SUSv3 says

顺便说一句,SUSv3 说

The KornShell-derived conditional command (double bracket [[]]) was removed from the shell command language description in an early proposal. Objections were raised that the real problem is misuse of the testcommand ([), and putting it into the shell is the wrong way to fix the problem. Instead, proper documentation and a new shell reserved word (!) are sufficient.

Tests that require multiple testoperations can be done at the shell level using individual invocations of the testcommand and shell logicals, rather than using the error-prone -oflag of test.

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

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

You'd need to write it this way, but testdoesn't support it:

你需要这样写,但测试不支持它:

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

testuses =for string equality, and more importantly it doesn't support pattern matching.

test使用=表示字符串相等,更重要的是它不支持模式匹配。

case/ esachas good support for pattern matching:

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

case $HOST in
user1|node*) echo yes ;;
esac

It has the added benefit that it doesn't depend on Bash, and the syntax is portable. From the Single Unix Specification, The Shell Command Language:

它有一个额外的好处,它不依赖于 Bash,并且语法是可移植的。来自单一 Unix 规范Shell 命令语言

case word in
    [(]pattern1) compound-list;;
    [[(]pattern[ | pattern] ... ) compound-list;;] ...
    [[(]pattern[ | pattern] ... ) compound-list]
esac