简体   繁体   English

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

[英]In Bash, how can I check if a string begins with some value?

I would like to check if a string begins with "node" eg "node001".我想检查一个字符串是否以“node”开头,例如“node001”。 Something like就像是

if [ $HOST == user* ]
  then
  echo yes
fi

How can I do it correctly?我怎样才能正确地做到这一点?


I further need to combine expressions to check if HOST is either "user1" or begins with "node"我还需要结合表达式来检查 HOST 是“user1”还是以“node”开头

if [ [[ $HOST == user1 ]] -o [[ $HOST == node* ]] ];
then
echo yes
fi

> > > -bash: [: too many arguments

How can I do it correctly?我怎样才能正确地做到这一点?

This snippet on the Advanced Bash Scripting Guide says: 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).

So you had it nearly correct;所以你几乎是正确的; you needed double brackets, not single brackets.你需要括号,而不是单括号。


With regards to your second question, you can write it this way:关于你的第二个问题,你可以这样写:

HOST=user1
if  [[ $HOST == user1 ]] || [[ $HOST == node* ]] ;
then
    echo yes1
fi

HOST=node001
if [[ $HOST == user1 ]] || [[ $HOST == node* ]] ;
then
    echo yes2
fi

Which will echo哪个会回响

yes1
yes2

Bash's if syntax is hard to get used to (IMO). Bash 的if语法很难习惯(IMO)。

If you're using a recent version of Bash (v3+), I suggest the Bash regex comparison operator =~ , for example,如果您使用的是最新版本的 Bash (v3+),我建议使用 Bash 正则表达式比较运算符=~ ,例如,

if [[ "$HOST" =~ ^user.* ]]; then
    echo "yes"
fi

To match this or that in a regex, use |要在正则表达式中匹配this or that ,请使用| , for example, , 例如,

if [[ "$HOST" =~ ^user.*|^host1 ]]; then
    echo "yes"
fi

Note - this is 'proper' regular expression syntax.注意 - 这是“正确的”正则表达式语法。

  • user* means use and zero-or-more occurrences of r , so use and userrrr will match. user*表示user的零次或多次出现,因此useuserrrr将匹配。
  • user.* means user and zero-or-more occurrences of any character, so user1 , userX will match. user.*表示user和零次或多次出现的任何字符,因此user1userX将匹配。
  • ^user.* means match the pattern user.* at the begin of $HOST. ^user.*表示匹配 $HOST 开头的模式user.*

If you're not familiar with regular expression syntax, try referring to this resource .如果您不熟悉正则表达式语法,请尝试参考此资源

Note that the Bash =~ operator only does regular expression matching when the right hand side is UNQUOTED .请注意,Bash =~运算符仅在右侧为UNQUOTED时进行正则表达式匹配。 If you do quote the right hand side, "any part of the pattern may be quoted to force it to be matched as a string.".如果您确实引用了右侧,则“可以引用模式的任何部分以强制将其作为字符串匹配。”。 You should not quote the right hand side even when doing parameter expansion.即使在进行参数扩展时,也不应引用右侧。

I always try to stick with POSIX sh instead of using Bash extensions, since one of the major points of scripting is portability (besides connecting programs, not replacing them).我总是尝试坚持使用 POSIX sh而不是使用 Bash 扩展,因为脚本的要点之一是可移植性(除了连接程序,而不是替换它们)。

In sh , there is an easy way to check for an "is-prefix" condition.sh中,有一种简单的方法可以检查“is-prefix”条件。

case $HOST in node*)
    # Your code here
esac

Given how old, arcane and crufty sh is (and Bash is not the cure: It's more complicated, less consistent and less portable), I'd like to point out a very nice functional aspect: While some syntax elements like case are built-in, the resulting constructs are no different than any other job.考虑到 sh 有多古老、晦涩难懂(而且 Bash 不是灵丹妙药:它更复杂、更不连贯且更不便携),我想指出一个非常好的功能方面:虽然一些语法元素(如case是内置的)在,由此产生的构造与任何其他工作没有什么不同。 They can be composed in the same way:它们可以用相同的方式组成:

if case $HOST in node*) true;; *) false;; esac; then
    # Your code here
fi

Or even shorter甚至更短

if case $HOST in node*) ;; *) false;; esac; then
    # Your code here
fi

Or even shorter (just to present ! as a language element -- but this is bad style now)甚至更短(只是为了呈现!作为语言元素——但现在这是不好的风格)

if ! case $HOST in node*) false;; esac; then
    # Your code here
fi

If you like being explicit, build your own language element:如果您喜欢明确,请构建自己的语言元素:

beginswith() { case $2 in "$1"*) true;; *) false;; esac; }

Isn't this actually quite nice?这真的不是很好吗?

if beginswith node "$HOST"; then
    # Your code here
fi

And since sh is basically only jobs and string-lists (and internally processes, out of which jobs are composed), we can now even do some light functional programming:而且由于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

This is elegant.这是优雅的。 Not that I'd advocate using sh for anything serious -- it breaks all too quickly on real world requirements (no lambdas, so we must use strings. But nesting function calls with strings is not possible, pipes are not possible, etc.)并不是说我主张将sh用于任何严重的事情——它在现实世界的要求上太快了(没有 lambda,所以我们必须使用字符串。但是用字符串嵌套函数调用是不可能的,管道是不可能的,等等)

You can select just the part of the string you want to check:您可以只选择要检查的字符串部分:

if [ "${HOST:0:4}" = user ]

For your follow-up question, you could use an OR :对于您的后续问题,您可以使用OR

if [[ "$HOST" == user1 || "$HOST" == node* ]]

I prefer the other methods already posted, but some people like to use:我更喜欢已经发布的其他方法,但有些人喜欢使用:

case "$HOST" in 
    user1|node*) 
            echo "yes";;
        *)
            echo "no";;
esac

Edit:编辑:

I've added your alternates to the case statement above我已将您的替代者添加到上面的案例陈述中

In your edited version you have too many brackets.在您编辑的版本中,括号太多。 It should look like this:它应该如下所示:

if [[ $HOST == user1 || $HOST == node* ]];

While I find most answers here quite correct, many of them contain unnecessary Bashisms.虽然我发现这里的大多数答案都非常正确,但其中许多都包含不必要的 Bashisms。 POSIX parameter expansion gives you all you need: POSIX 参数扩展为您提供所需的一切:

[ "${host#user}" != "${host}" ]

and

[ "${host#node}" != "${host}" ]

${var#expr} strips the smallest prefix matching expr from ${var} and returns that. ${var#expr}${var}中去除与expr匹配的最小前缀并返回它。 Hence if ${host} does not start with user ( node ), ${host#user} ( ${host#node} ) is the same as ${host} .因此,如果${host}user ( node ) 开头,则${host#user} ( ${host#node} ) 与${host}相同。

expr allows fnmatch() wildcards, thus ${host#node??} and friends also work. expr允许fnmatch()通配符,因此${host#node??}和朋友也可以使用。

Since # has a meaning in Bash, I got to the following solution.由于#在 Bash 中具有含义,因此我得到了以下解决方案。

In addition I like better to pack strings with "" to overcome spaces, etc.此外,我更喜欢用 "" 打包字符串以克服空格等。

A="#sdfs"
if [[ "$A" == "#"* ]];then
    echo "Skip comment line"
fi

Adding a tiny bit more syntax detail to Mark Rushakoff's highest rank answer.为 Mark Rushakoff 的最高等级答案添加一点点语法细节。

The expression表达方式

$HOST == node*

Can also be written as也可以写成

$HOST == "node"*

The effect is the same.效果是一样的。 Just make sure the wildcard is outside the quoted text.只要确保通配符在引用的文本之外。 If the wildcard is inside the quotes it will be interpreted literally (ie not as a wildcard).如果通配符引号内,它将按字面意思解释(即不作为通配符)。

@OP, for both your questions you can use case/esac: @OP,对于您的两个问题,您都可以使用 case/esac:

string="node001"
case "$string" in
  node*) echo "found";;
  * ) echo "no node";;
esac

Second question第二个问题

case "$HOST" in
 node*) echo "ok";;
 user) echo "ok";;
esac

case "$HOST" in
 node*|user) echo "ok";;
esac

Or Bash 4.0重击 4.0

case "$HOST" in
 user) ;&
 node*) echo "ok";;
esac
if [ [[ $HOST == user1 ]] -o [[ $HOST == node* ]] ];
then
echo yes
fi

doesn't work, because all of [ , [[ , and test recognize the same nonrecursive grammar.不起作用,因为所有[[[test都识别相同的非递归语法。 See section CONDITIONAL EXPRESSIONS on your Bash man page.请参阅 Bash 手册页上的条件表达式部分。

As an aside, the SUSv3 says顺便说一句,SUSv3 说

The KornShell-derived conditional command (double bracket [[]] ) was removed from the shell command language description in an early proposal.在早期的提案中,KornShell 派生的条件命令(双括号[[]] )已从 shell 命令语言描述中删除。 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.有人提出反对,认为真正的问题是滥用测试命令 ( [ ),将其放入 shell 是解决问题的错误方法。 Instead, proper documentation and a new shell reserved word ( ! ) are sufficient.相反,适当的文档和新的 shell 保留字 ( ! ) 就足够了。

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 .需要多个测试操作的测试可以在 shell 级别使用test命令和 shell 逻辑的单独调用来完成,而不是使用test的容易出错的-o标志。

You'd need to write it this way, but test doesn't support it:你需要这样写,但test不支持它:

if [ $HOST == user1 -o $HOST == node* ];
then
echo yes
fi

test uses = for string equality, and more importantly it doesn't support pattern matching. test使用=表示字符串相等,更重要的是它不支持模式匹配。

case / esac has good support for pattern matching: case / esac对模式匹配有很好的支持:

case $HOST in
user1|node*) echo yes ;;
esac

It has the added benefit that it doesn't depend on Bash, and the syntax is portable.它还有一个额外的好处是它不依赖于 Bash,并且语法是可移植的。 From the Single Unix Specification , The Shell Command Language :来自单一 Unix 规范Shell 命令语言

case word in
    [(]pattern1) compound-list;;
    [[(]pattern[ | pattern] ... ) compound-list;;] ...
    [[(]pattern[ | pattern] ... ) compound-list]
esac

grep

Forgetting performance, this is POSIX and looks nicer than case solutions:忘记性能,这是 POSIX,看起来比case解决方案更好:

mystr="abcd"
if printf '%s' "$mystr" | grep -Eq '^ab'; then
  echo matches
fi

Explanation:解释:

I tweaked @markrushakoff's answer to make it a callable function:我调整了@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" == "" ]]
}

Use it like this:像这样使用它:

$ 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

Here is a more complex version that provides for a specified default value:这是一个提供指定默认值的更复杂的版本:

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* ]]
}

Use it like this:像这样使用它:

$ 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

Keep it simple把事情简单化

word="appel"

if [[ $word = a* ]]
then
  echo "Starts with a"
else
  echo "No match"
fi

你可以做的另一件事是cat出你是什么呼应和管道与inline cut -c 1-1

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何检查字符串是否以 Swift 5 中的字母开头? - How to Check if String begins with Alphabet Letter in Swift 5? 如何检查 Bash 或 Unix shell 中字符串的第一个字符? - How can I check the first character in a string in Bash or Unix shell? 如何在Python中检查字符串中是否包含某些相同的字符? - How can i check if a string has some of the same characters in it in Python? 如何在某些编码中检查字符串是否可编码? - How can I check if a String is encodable in some encoding? 如何检查const char *是否以特定字符串开头? (C ++) - How do I check if a const char* begins with a specific string? (C++) 检查字符串是否以标点符号开头(Javascript) - Check if string begins with punctuation (Javascript) 如何搜索在某个字符串的索引之前开始的正则表达式匹配? - How can I search for a Regular Expression match that begins before a certain index of a string? 如何检查字符串是否包含 VBScript 中的十六进制值? - How can I check if a string contains an hexadecimal value in VBScript? 如何在razor视图中检查字符串值? - How can I check string value in razor view? 如何在Bash中将字符串与正则表达式匹配? - How can I match a string with a regex in Bash?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM