我想检查字符串是否以“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
如何正确地做到这一点?
答案 0 :(得分:863)
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).
所以你已经几乎正确了;你需要双括号,而不是单括号。
关于你的第二个问题,你可以这样写:
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)。
答案 1 :(得分:169)
如果您使用的是最近的bash(v3 +),我建议使用bash正则表达式比较运算符=~
,即
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.*
表示匹配$ HOST开头的模式user.*
。如果您不熟悉正则表达式语法,请尝试参考this resource。
注意 - 如果你将每个新问题都问为一个新问题,它会更好,它会使stackoverflow更整洁,更有用。您始终可以包含一个返回上一个问题的链接以供参考。
答案 2 :(得分:106)
我总是试图坚持使用POSIX sh而不是使用bash扩展,因为脚本的一个主要点是可移植性。 (除了连接程序,而不是替换它们)
在sh中,有一种简单的方法可以检查“is-prefix”条件。
case $HOST in node*)
your code here
esac
考虑到古老,神秘和狡猾的sh(并且bash不是治愈方法:它更复杂,更不一致,更不便携),我想指出一个非常好的功能方面:虽然有些语法元素如{ {1}}是内置的,结果构造与任何其他工作没有什么不同。它们可以用相同的方式组成:
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; }
由于sh基本上只是作业和字符串列表(以及内部进程,其中包含作业),我们现在甚至可以进行一些轻量函数编程:
if beginswith node "$HOST"; then
your code here
fi
这很优雅。不是说我主张使用sh来表示严重的事情 - 它在现实世界的要求上打得太快(没有lambdas,所以必须使用字符串。但是用字符串嵌套函数调用是不可能的,管道是不可能的......)< / p>
答案 3 :(得分:67)
您可以只选择要检查的字符串部分:
if [ ${HOST:0:4} = user ]
对于您的后续问题,您可以使用OR:
if [[ $HOST == user1 || $HOST == node* ]]
答案 4 :(得分:55)
我更喜欢已发布的其他方法,但有些人喜欢使用:
case "$HOST" in
user1|node*)
echo "yes";;
*)
echo "no";;
esac
修改强>
我已将您的替代词添加到上面的案例陈述中
在您编辑的版本中,您有太多括号。它应该是这样的:
if [[ $HOST == user1 || $HOST == node* ]];
答案 5 :(得分:28)
因为#在bash中有意义所以我得到了以下解决方案 另外,我更喜欢用“”打包字符串以克服空格等。
A="#sdfs"
if [[ "$A" == "#"* ]];then
echo "skip comment line"
fi
答案 6 :(得分:28)
虽然我发现这里的大多数答案都很正确,但其中很多都含有不必要的基础。 POSIX parameter expansion为您提供所需的一切:
[ "${host#user}" != "${host}" ]
和
[ "${host#node}" != "${host}" ]
${var#expr}
从expr
中删除与${var}
匹配的最小前缀并返回该前缀。因此,如果${host}
不以user
(node
)开头,则${host#user}
(${host#node}
)与{{1}相同}}
${host}
允许fnmatch()
个通配符,因此expr
和朋友也可以使用。
答案 7 :(得分:8)
@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
OR Bash 4.0
case "$HOST" in
user) ;&
node*) echo "ok";;
esac
答案 8 :(得分:6)
if [ [[ $HOST == user1 ]] -o [[ $HOST == node* ]] ];
then
echo yes
fi
不起作用,因为所有 [, [[和 test )都识别相同的非递归语法。请参阅bash手册页中的 CONDITIONAL EXPRESSIONS 部分。
另外,SUSv3说
KornShell派生的条件命令(双括号 [[]] )已从早期提案中的shell命令语言描述中删除。有人反对提出真正的问题是滥用 test 命令( [),并将其放入shell中是解决问题的错误方法。相反,适当的文档和新的shell保留字(!)就足够了。
需要多个 test 操作的测试可以在shell级别使用 test 命令和shell逻辑的单独调用来完成,而不是使用容易出错的 -o test 的标志。
您需要以这种方式编写,但 test 不支持它:
if [ $HOST == user1 -o $HOST == node* ];
then
echo yes
fi
test 使用 = 表示字符串相等,更重要的是它不支持模式匹配。
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
答案 9 :(得分:6)
在Mark Rushakoff的最高排名答案中添加了更多语法细节。
表达式
$HOST == node*
也可以写为
$HOST == "node"*
效果是一样的。只要确保通配符在引号之外即可。如果通配符位于内,则引号将按字面意义进行解释(即不作为通配符)。
答案 10 :(得分:1)
我调整了@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
答案 11 :(得分:0)
--Searches and deletes table TABLEAU_LCC_LEAD_TIME if it exists
DECLARE
does_not_exist EXCEPTION;
PRAGMA EXCEPTION_INIT (does_not_exist, -942);
BEGIN
EXECUTE IMMEDIATE 'DROP TABLE TABLEAU_DOC_LEAD_TIMES';
EXCEPTION
WHEN does_not_exist
THEN
NULL;
END;
/
忘记了性能,这是POSIX,看起来比grep
解决方案好:
case
说明:
mystr="abcd"
if printf '%s' "$mystr" | grep -Eq '^ab'; then
echo matches
fi
以防止printf '%s'
扩展反斜杠转义符:bash printf literal verbatim string printf
阻止将匹配回显到stdout:How to check if a file contains a specific string using Bash grep -q
启用扩展的正则表达式,我们需要grep -E
答案 12 :(得分:-5)
你可以做的另一件事是cat
你正在回应的东西和inline cut -c 1-1