代码之家  ›  专栏  ›  技术社区  ›  Tim unnamed eng

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

  •  586
  • Tim unnamed eng  · 技术社区  · 15 年前

    我想检查字符串是否以“node”开头,例如“node001”。类似的东西

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

    我该怎么做才对呢?


    我还需要组合表达式来检查主机是“user1”还是以“node”开头

    if [ [[ $HOST == user1 ]] -o [[ $HOST == node* ]] ];  
    then  
    echo yes 
    fi
    
    > > > -bash: [: too many arguments
    

    如何正确操作?

    11 回复  |  直到 6 年前
        1
  •  816
  •   Marco Bonelli    8 年前

    关于 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
    

    巴什的 if 语法很难习惯(IMO)。

        2
  •  161
  •   dimwittedanimal    6 年前

    如果您使用的是最新的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 如此 使用 userrrr 将匹配。
    • user.* 方法 user 以及任何字符的零次或多次出现,所以 user1 , userX 将匹配。
    • ^user.* 意味着匹配模式 用户* 在$host的开头。

    如果您不熟悉正则表达式语法,请尝试引用 this resource .

    注意-如果你把每个新问题作为一个新问题来问,它会使stackoverflow更整洁,更有用。您可以始终包含一个指向上一个问题的链接,以供参考。

        3
  •  95
  •   Jo So    8 年前

    我总是坚持使用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,所以必须使用字符串)。但不能使用字符串嵌套函数调用,不能使用管道…)

        4
  •  64
  •   martin clayton egrunin    15 年前

    您可以只选择要检查的字符串部分:

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

    对于后续问题,您可以使用 OR :

    if [[ $HOST == user1 || $HOST == node* ]]
    
        5
  •  54
  •   Dennis Williamson    15 年前

    我更喜欢已经发布的其他方法,但有些人喜欢使用:

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

    编辑:

    我已经在上面的案例陈述中添加了你的替代者

    在编辑的版本中,括号太多。它应该是这样的:

    if [[ $HOST == user1 || $HOST == node* ]];
    
        6
  •  28
  •   ozma    11 年前

    因为在bash中有意义,所以我得出了以下解决方案。
    此外,我更喜欢用“”填充字符串以克服空格等。

    A="#sdfs"
    if [[ "$A" == "#"* ]];then
        echo "skip comment line"
    fi
    
        7
  •  26
  •   dhke    9 年前

    虽然我在这里发现大多数答案都是正确的,但其中许多都包含不必要的害羞。 POSIX parameter expansion 为您提供所需的一切:

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

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

    ${var#expr} 去掉最小的前缀匹配 expr ${var} 然后返回。因此如果 ${host} 从开始 user ( node ) ${host#user} ( ${host#node} )与 ${主机} .

    EXPR 允许 fnmatch() 因此,通配符 ${host#node??} 朋友也在工作。

        8
  •  8
  •   ghostdog74    15 年前

    @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
    

    或巴什4

    case "$HOST" in
     user) ;& 
     node*) echo "ok";; 
    esac
    
        9
  •  6
  •   just somebody    15 年前
    if [ [[ $HOST == user1 ]] -o [[ $HOST == node* ]] ];  
    then  
    echo yes 
    fi
    

    不起作用,因为 [ , [[ 测试 识别相同的非递归语法。见节 条件表达式 在你的bash主页上。

    作为旁白,SUSV3说

    Kornhell派生的条件命令(双括号 [] )在早期的建议中从shell命令语言描述中删除。有人提出反对意见,认为真正的问题是滥用 测试 命令( [ 把它放进壳里是解决问题的错误方法。相反,适当的文档和一个新的shell保留字( ! )足够了。

    需要多个的测试 测试 操作可以在shell级别使用 测试 命令和shell逻辑,而不是使用容易出错的 -O 测试 .

    你得这样写,但是 测试 不支持:

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

    测试 使用 = 对于字符串相等,更重要的是它不支持模式匹配。

    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
    
        10
  •  6
  •   MrPotatoHead    7 年前

    在马克·拉沙科夫的最高级答案中增加了一点语法细节。

    表达式

    $HOST == node*
    

    也可以写为

    $HOST == "node"*
    

    效果是一样的。只需确保通配符在引用文本之外。如果通配符是 里面 它将被逐字解释为引号(即,不是通配符)。

        11
  •  -5
  •   rayryeng    9 年前

    你能做的另一件事是 cat 你在用什么来回响和吹奏 inline cut -c 1-1