In bash, how can I check if a string begins with some value?
我想检查字符串是否以"node"开头,例如"node001"。类似的东西
1 2 3 4 | if [ $HOST == user* ] then echo yes fi |
我怎样才能正确地做?
我还需要组合表达式来检查主机是"user1"还是以"node"开头
1 2 3 4 5 6 | if [ [[ $HOST == user1 ]] -o [[ $HOST == node* ]] ]; then echo yes fi > > > -bash: [: too many arguments |
如何正确操作?
《高级bash脚本编写指南》中的这段代码指出:
1 2 3 4 5 | # 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). |
所以你几乎正确了;你需要双括号,而不是单括号。
关于第二个问题,您可以这样写:
1 2 3 4 5 6 7 8 9 10 11 | HOST=user1 if [[ $HOST == user1 ]] || [[ $HOST == node* ]] ; then echo yes1 fi HOST=node001 if [[ $HOST == user1 ]] || [[ $HOST == node* ]] ; then echo yes2 fi |
哪个会回响
1 2 | yes1 yes2 |
bash的
如果您使用的是最新的bash(v3+),我建议使用bash regex比较运算符
1 2 3 | if [["$HOST" =~ ^user.* ]]; then echo"yes" fi |
为了匹配regex中的
1 2 3 | if [["$HOST" =~ ^user.*|^host1 ]]; then echo"yes" fi |
注意-这是"正确"的正则表达式语法。
user* 表示use 和r 的零个或多个出现,因此use 和userrrr 将匹配。user.* 表示user 和任何字符的零个或多个出现,因此user1 和userX 将匹配。^user.* 表示匹配$host开头的模式user.* 。
如果您不熟悉正则表达式语法,请尝试引用此资源。
注意-如果你把每个新问题作为一个新问题来问,它会使stackoverflow更整洁,更有用。您可以始终包含一个指向上一个问题的链接,以供参考。
我总是坚持使用posix sh而不是使用bash扩展,因为脚本的一个主要点是可移植性。(除了连接程序,不替换它们)
在sh中,有一种简单的方法可以检查"is prefix"条件。
1 2 3 | case $HOST in node*) your code here esac |
考虑到sh的古老、神秘和粗糙(bash不是解决方法:它更复杂、更不一致、更不可移植),我想指出一个非常好的功能方面:虽然像
1 2 3 | if case $HOST in node*) true;; *) false;; esac; then your code here fi |
甚至更短
1 2 3 | if case $HOST in node*) ;; *) false;; esac; then your code here fi |
甚至更短(只是将
1 2 3 | if ! case $HOST in node*) false;; esac; then your code here fi |
如果您喜欢显式,请构建自己的语言元素:
1 | beginswith() { case $2 in"$1"*) true;; *) false;; esac; } |
这不是很好吗?
1 2 3 | if beginswith node"$HOST"; then your code here fi |
由于sh基本上只是作业和字符串列表(以及内部进程,其中的作业是由这些进程组成的),我们现在甚至可以进行一些简单的函数式编程:
1 2 3 4 5 6 7 8 9 10 11 12 | 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,所以必须使用字符串)。但不能使用字符串嵌套函数调用,不能使用管道…)
您可以只选择要检查的字符串部分:
1 | if [ ${HOST:0:4} = user ] |
对于后续问题,您可以使用或:
1 | if [[ $HOST == user1 || $HOST == node* ]] |
我更喜欢已经发布的其他方法,但有些人喜欢使用:
1 2 3 4 5 6 | case"$HOST" in user1|node*) echo"yes";; *) echo"no";; esac |
编辑:
我已经在上面的案例陈述中添加了你的替代者
在编辑的版本中,括号太多。它应该是这样的:
1 | if [[ $HOST == user1 || $HOST == node* ]]; |
因为在bash中有意义,所以我得出了以下解决方案。此外,我更喜欢用"克服空格等"来包装字符串。
1 2 3 4 | A="#sdfs" if [["$A" =="#"* ]];then echo"skip comment line" fi |
虽然我在这里发现大多数答案都是正确的,但其中许多都包含不必要的害羞。posix参数扩展为您提供了所需的一切:
1 | ["${host#user}" !="${host}" ] |
和
1 | ["${host#node}" !="${host}" ] |
@op,对于这两个问题,您都可以使用case/esac
1 2 3 4 5 | string="node001" case"$string" in node*) echo"found";; * ) echo"no node";; esac |
第二个问题
1 2 3 4 5 6 7 8 | case"$HOST" in node*) echo"ok";; user) echo"ok";; esac case"$HOST" in node*|user) echo"ok";; esac |
或巴什4
1 2 3 4 | case"$HOST" in user) ;& node*) echo"ok";; esac |
在马克·拉沙科夫的最高级答案中增加了一点语法细节。
表达式
1 | $HOST == node* |
也可以写为
1 | $HOST =="node"* |
效果是一样的。只需确保通配符在引用文本之外。如果通配符在引号内,则将按字面解释(即,不作为通配符)。
1 2 3 4 | if [ [[ $HOST == user1 ]] -o [[ $HOST == node* ]] ]; then echo yes fi |
不起作用,因为所有的[、[和测试都能识别相同的非递归语法。请参见bash手册页中的条件表达式一节。
作为旁白,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 test command ([), 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 test operations can be done at the shell level using individual invocations of the test command and shell logicals, rather than using the error-prone -o flag of test.
您需要这样写,但测试不支持它:
1 2 3 4 | if [ $HOST == user1 -o $HOST == node* ]; then echo yes fi |
测试使用=进行字符串相等,更重要的是它不支持模式匹配。
1 2 3 | case $HOST in user1|node*) echo yes ;; esac |
它还有一个额外的好处,即它不依赖于bash,语法是可移植的。从单个UNIX规范中,shell命令语言:
1 2 3 4 5 | case word in [(]pattern1) compound-list;; [[(]pattern[ | pattern] ... ) compound-list;;] ... [[(]pattern[ | pattern] ... ) compound-list] esac |
你能做的另一件事是用