我想检查字符串是否以“ node”开头,例如“ 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
如何正确执行?
我想检查字符串是否以“ node”开头,例如“ 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
如何正确执行?
Answers:
《高级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)。
[[ $a == z* ]]
和之间有功能上的区别[[ $a == "z*" ]]
吗?换句话说:它们的工作方式不同吗?当您说“ $ a等于z *”时,这是什么意思?
[[ $a == *com ]]
如果您使用的是最新版本的Bash(v3 +),则建议使用Bash regex比较运算符=~
,例如,
if [[ "$HOST" =~ ^user.* ]]; then
echo "yes"
fi
要匹配this or that
正则表达式,请使用|
,例如,
if [[ "$HOST" =~ ^user.*|^host1 ]]; then
echo "yes"
fi
注意-这是“正确”的正则表达式语法。
user*
的平均值use
和零个或多个出现r
,因此use
和userrrr
将匹配。user.*
装置user
和零或更多的出现任意字符,那么user1
,userX
将匹配。^user.*
表示匹配user.*
$ HOST开头的模式。如果您不熟悉正则表达式语法,请尝试参考此资源。
=~
运算符仅在右侧为UNQUOTED时执行正则表达式匹配。如果确实引用了右侧,则“可能会引用该模式的任何部分以强制将其匹配为字符串。” (1.)确保始终将正则表达式放在右引号之外;(2。)如果将正则表达式存储在变量中,请确保在进行参数扩展时不引用右手边。
我始终尝试使用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,所以我们必须使用字符串。但是不能使用字符串嵌套函数调用,不能使用管道,等等)。
case $HOST in user01 | node* ) ...
if case $HOST in node*) true;; *) false;; esac; then
我到处都看过它,在我看来,它看起来有些皱缩。
case
命令是命令,所以它们可以进入if ... then
。
beginswith() { case "$2" in "$1"*) true;; *) false;; esac; }
否则应使用$1
文字*
,?
否则可能给出错误的答案。
我更喜欢已经发布的其他方法,但是有些人喜欢使用:
case "$HOST" in
user1|node*)
echo "yes";;
*)
echo "no";;
esac
编辑:
我已将您的替代品添加到上述案例声明中
在您编辑的版本中,括号太多。它看起来应该像这样:
if [[ $HOST == user1 || $HOST == node* ]];
虽然我发现这里的大多数答案是正确的,但其中许多包含不必要的Bashisms。POSIX参数扩展可满足您的所有需求:
[ "${host#user}" != "${host}" ]
和
[ "${host#node}" != "${host}" ]
${var#expr}
去掉最小的前缀匹配expr
从${var}
返回这一点。因此,如果${host}
没有不下手user
(node
), (${host#user}
)${host#node}
是一样的${host}
。
expr
允许使用fnmatch()
通配符,因此${host#node??}
和朋友也可以工作。
[[ $host == user* ]]
可能是必要的,因为它比更具可读性[ "${host#user}" != "${host}" ]
。因此,如果您控制执行脚本的环境(以的最新版本为目标bash
),则最好使用前者。
has_prefix()
函数,并且不再关注它。
由于#
在Bash中具有含义,因此我获得了以下解决方案。
另外,我更喜欢用“”来包装字符串,以克服空格等问题。
A="#sdfs"
if [[ "$A" == "#"* ]];then
echo "Skip comment line"
fi
blah:
,看起来这就是答案!
@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
;&
只有在击> = 4,可用
if [ [[ $HOST == user1 ]] -o [[ $HOST == node* ]] ];
then
echo yes
fi
不工作的,因为所有的[
,[[
以及test
识别相同的非递归语法。请参见Bash手册页上的“ 条件表达式 ” 部分。
顺便说一句,SUSv3说
在早期的提议中,从KornShell派生的条件命令(双括号[[]])已从Shell命令语言描述中删除。有人提出反对意见,认为真正的问题是滥用测试命令([),将其放入外壳是解决问题的错误方法。而是使用适当的文档和一个新的shell保留字(!)就足够了。
可以使用单独的test命令和shell逻辑调用在shell级别上完成需要多次测试操作的测试,而不是使用test的容易出错的-o标志。
您需要以这种方式编写它,但是测试不支持它:
if [ $HOST == user1 -o $HOST == node* ];
then
echo yes
fi
测试使用=来实现字符串相等性,更重要的是,它不支持模式匹配。
case
/ esac
对模式匹配有很好的支持:
case $HOST in
user1|node*) echo yes ;;
esac
它具有不依赖Bash的附加优点,并且语法可移植。根据Single Unix规范,Shell命令语言:
case word in
[(]pattern1) compound-list;;
[[(]pattern[ | pattern] ... ) compound-list;;] ...
[[(]pattern[ | pattern] ... ) compound-list]
esac
[
并且test
是Bash内置程序以及外部程序。尝试type -a [
。
if [ -z $aa -or -z $bb ]
; ...给出“ bash:[:-或:期望的二进制运算符 ”;但是if [ -z "$aa" -o -z "$bb" ] ; ...
过去了。
grep
忘了性能,这是POSIX,看起来比case
解决方案好:
mystr="abcd"
if printf '%s' "$mystr" | grep -Eq '^ab'; then
echo matches
fi
说明:
printf '%s'
防止printf
扩展反斜杠转义符:Bash printf文字逐字字符串grep -q
防止将匹配回显到stdout:如何使用Bash检查文件是否包含特定字符串grep -E
启用扩展的正则表达式,这是我们需要的 ^
我调整了@markrushakoff的答案,使其成为可调用的函数:
function yesNo {
# Prompts user with $1, returns true if response starts with y or Y or is empty string
read -e -p "
$1 [Y/n] " YN
[[ "$YN" == y* || "$YN" == Y* || "$YN" == "" ]]
}
像这样使用它:
$ if yesNo "asfd"; then echo "true"; else echo "false"; fi
asfd [Y/n] y
true
$ if yesNo "asfd"; then echo "true"; else echo "false"; fi
asfd [Y/n] Y
true
$ if yesNo "asfd"; then echo "true"; else echo "false"; fi
asfd [Y/n] yes
true
$ if yesNo "asfd"; then echo "true"; else echo "false"; fi
asfd [Y/n]
true
$ if yesNo "asfd"; then echo "true"; else echo "false"; fi
asfd [Y/n] n
false
$ if yesNo "asfd"; then echo "true"; else echo "false"; fi
asfd [Y/n] ddddd
false
这是提供指定默认值的更复杂的版本:
function toLowerCase {
echo "$1" | tr '[:upper:]' '[:lower:]'
}
function yesNo {
# $1: user prompt
# $2: default value (assumed to be Y if not specified)
# Prompts user with $1, using default value of $2, returns true if response starts with y or Y or is empty string
local DEFAULT=yes
if [ "$2" ]; then local DEFAULT="$( toLowerCase "$2" )"; fi
if [[ "$DEFAULT" == y* ]]; then
local PROMPT="[Y/n]"
else
local PROMPT="[y/N]"
fi
read -e -p "
$1 $PROMPT " YN
YN="$( toLowerCase "$YN" )"
{ [ "$YN" == "" ] && [[ "$PROMPT" = *Y* ]]; } || [[ "$YN" = y* ]]
}
像这样使用它:
$ if yesNo "asfd" n; then echo "true"; else echo "false"; fi
asfd [y/N]
false
$ if yesNo "asfd" n; then echo "true"; else echo "false"; fi
asfd [y/N] y
true
$ if yesNo "asfd" y; then echo "true"; else echo "false"; fi
asfd [Y/n] n
false