在bash中,如何检查一个string是否以某个值开始?
我想检查一个string是否以“node”开头,例如“node001”。 就像是
if [ $HOST == user* ] then echo yes fi
我怎样才能正确地做到这一点?
我还需要结合expression式来检查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的语法很难习惯(IMO)。
如果你使用最近的bash(v3 +),build议bash正则expression式比较运算符=~
,即
if [[ "$HOST" =~ ^user.* ]]; then echo "yes" fi
要匹配this or that
在正则expression式中使用|
即,
if [[ "$HOST" =~ ^user.*|^host1 ]]; then echo "yes" fi
注意 – 这是“正确的”正则expression式语法。
-
user*
表示use
r
和零次或多次出现,所以use
和userrrr
会匹配。 -
user.*
表示任何字符的user
和零次或多次出现,所以user1
,userX
将匹配。 -
^user.*
表示匹配$ HOST开头的模式user.*
。
如果您不熟悉正则expression式语法,请尝试引用此资源 。
注意 – 如果你将每个新问题作为一个新问题提出来,那么更好的做法是使计算器更加整洁和更有用。 您可以随时将链接添加回上一个问题以供参考。
我更喜欢已经发布的其他方法,但有些人喜欢使用:
case "$HOST" in user1|node*) echo "yes";; *) echo "no";; esac
编辑:
我已经在上面的case语句中添加了你的替代者
在你编辑的版本中,你有太多的括号。 它应该是这样的:
if [[ $HOST == user1 || $HOST == node* ]];
您只能select要检查的string的一部分:
if [ ${HOST:0:4} = user ]
对于你的后续问题,你可以使用OR :
if [[ $HOST == user1 || $HOST == node* ]]
我总是试图坚持使用POSIX sh,而不是使用bash扩展,因为脚本的一个主要点是可移植性。 (除了连接程序,不能replace它们)
在sh中,有一个简单的方法来检查“is-prefix”条件。
case $HOST in node*) your code here esac
鉴于年龄,神秘和笨重sh(而且bash不是治愈方法:它更复杂,更不一致,更不便携),我想指出一个非常好的function方面:虽然内置了一些语法元素,所得到的结构与其他任何工作没有区别。 他们可以用相同的方式组成:
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
如果你喜欢明确,build立你自己的语言元素:
beginswith() { case $2 in "$1"*) true;; *) false;; esac; }
这不是很好吗?
if beginswith node "$HOST"; then your code here fi
而且由于sh基本上只是作业和string列表(以及内部处理,哪些作业是由其组成的),我们现在甚至可以做一些轻量级的函数式编程:
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来处理任何严重的事情 – 它在现实世界的要求中不能太快(没有lambdaexpression式,所以必须使用string,但是用string嵌套函数是不可能的,pipe道是不可能的)
因为#在bash中有一个含义我得到了以下解决scheme。
此外,我更喜欢用“”来包装string来克服空间等。
A="#sdfs" if [[ "$A" == "#"* ]];then echo "skip comment line" fi
虽然我在这里find大多数答案都是非常正确的,但是其中很多答案都是不必要的。 POSIX参数扩展为您提供所有您所需要的:
[ "${host#user}" != "${host}" ]
和
[ "${host#node}" != "${host}" ]
${var#expr}
从${var}
剥离最小的前缀匹配expr
并返回。 因此,如果${host}
不以user
( node
)开始,则${host#user}
( ${host#node}
)与${host}
相同。
expr
允许fnmatch()
通配符,因此${host#node??}
和朋友也可以工作。
@OP,对于你的问题你可以使用case / esac
string="node001" case "$string" in node*) echo "found";; * ) echo "no node";; esac
第二个问题
case "$HOST" in node*) echo "ok";; user) echo "ok";; esac case "$HOST" in node*|user) echo "ok";; esac
或Bash 4.0
case "$HOST" in user) ;& node*) echo "ok";; esac
if [ [[ $HOST == user1 ]] -o [[ $HOST == node* ]] ]; then echo yes fi
不起作用,因为所有的[ , [[和testing都认出了同样的非recursion语法。 请参阅bash手册页中的CONDITIONAL EXPRESSIONS部分。
另外,SUSv3说
在早期的提议中,从shell命令语言描述中删除了KornShell派生的条件命令(双括号[[]] )。 反对意见认为,真正的问题是滥用testing命令( [ ),并将其放入shell是解决问题的错误方法。 相反,正确的文档和一个新的shell保留字( ! )就足够了。
需要多个testing操作的testing可以在shell级别使用testing命令和shell逻辑的单独调用来完成,而不是使用testing的错误倾向-o标志。
你需要这样写,但是testing不支持:
if [ $HOST == user1 -o $HOST == node* ]; then echo yes fi
testing使用= forstring相等,更重要的是它不支持模式匹配。
case
/ esac
对模式匹配有很好的支持:
case $HOST in user1|node*) echo yes ;; esac
它具有附加的好处,它不依赖于bash,语法是可移植的。 从单一Unix规范,Shell命令语言:
case word in [(]pattern1) compound-list;; [[(]pattern[ | pattern] ... ) compound-list;;] ... [[(]pattern[ | pattern] ... ) compound-list] esac
你可以做的另一件事是找出你正在呼应的内容和pipe道inline cut -c 1-1