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
In Bash, how can I check if a string begins with some value?
提问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 if
syntax 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 that
in a regex, use |
, for example,
要匹配this or that
正则表达式,请使用|
,例如,
if [[ "$HOST" =~ ^user.*|^host1 ]]; then
echo "yes"
fi
Note - this is 'proper' regular expression syntax.
注意 - 这是“正确的”正则表达式语法。
user*
meansuse
and zero-or-more occurrences ofr
, souse
anduserrrr
will match.user.*
meansuser
and zero-or-more occurrences of any character, souser1
,userX
will match.^user.*
means match the patternuser.*
at the begin of $HOST.
user*
意味着use
和零次或多次出现r
,所以use
和userrrr
将匹配。user.*
表示user
和零次或多次出现的任何字符,因此user1
,userX
将匹配。^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 sh
instead 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 case
are 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 sh
is 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 sh
for 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
回答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 expr
from ${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}
没有不下手user
(node
), (${host#user}
)${host#node}
是一样的${host}
。
expr
allows 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 test
recognize 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
/ esac
has 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