在bash中,如何检查字符串是否以某个值开头?

时间:2010-01-31 16:12:47

标签: string bash comparison

我想检查字符串是否以“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

如何正确地做到这一点?

13 个答案:

答案 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*表示user出现零次或多次,因此useuserrrr会匹配。
  • user.*表示user并且出现任意字符零次或多次,因此user1userX将匹配。
  • ^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} usernode)开头,则${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

说明:

答案 12 :(得分:-5)

你可以做的另一件事是cat你正在回应的东西和inline cut -c 1-1

的管道