【问题标题】:Split 1 argument into 2 arguments using regexp in a bash script在 bash 脚本中使用正则表达式将 1 个参数拆分为 2 个参数
【发布时间】:2012-07-10 14:58:08
【问题描述】:

这是我的情况。目前,我有一个接受两个参数的脚本:书名和章节名。例如:

$ myscript book1 chap1

现在,由于需要很长时间才能解释的原因,我希望我的脚本能够采用以下格式的单个参数:{book name}.{chapter name}。例如:

$ myscript book1.chap1

对我来说困难在于我不知道如何将字符串 $1=abc.xyz 转换为两个单独的变量,$var1=abc 和 $var2=xyz。我该怎么做?

【问题讨论】:

    标签: regex bash


    【解决方案1】:

    如果只是两个标签,你可以使用 bash 表达式

    arg=$1
    beforedot=${arg%.*}
    afterdot=${arg#*.}
    

    它比cut 更快,因为它是一个内置的shell。请注意,这会将 first 最后一个点之前的所有内容放入beforedot,并将之后的所有内容放入afterdot。

    编辑:

    如果您想按任意数量的标记进行拆分,还有一个替换/重新解释结构:

    string=a.b.c.d.e
    tokens=(${string//\./ })
    

    您将点替换为空格,然后由于它周围的括号而被解释为数组声明+定义。

    但是我发现这对于 bash 的兄弟姐妹和后代来说不太便携。例如,它不适用于我最喜欢的 shell,zsh。

    数组需要用大括号取消引用并从0开始索引:

    echo "Third token: ${tokens[2]}"
    

    您也可以通过使用 [@] 取消引用整个数组来循环它们:

    for i in ${tokens[@]}
    do
        # do stuff
    done
    

    【讨论】:

    • 如果字符串包含多个点会怎样?
    • 如果$arg="start.middle.end",然后是$beforedot="start.middle",然后是$afterdot="middle.end"。中间部分将被复制。
    • @mouviciel:点之间的部分最终出现在两个变量中(例如,如果 $1="a.b.c.d",它将设置 $beforedot="a.b.c" 和 $afterdot="b.c.d")。如果您使用beforedot=${arg%%.*},您将只得到$beforedot 中第一个点之前的部分,这可能更有意义。
    • 这种东西的名字是参数扩展,想进一步阅读的人:wiki.bash-hackers.org/syntax/pe
    【解决方案2】:

    为了完整性,既然您询问了正则表达式方法:

    pattern='^([^.]*)\.(.*)'
    [[ $1 =~ $pattern ]]
    book=${BASH_REMATCH[1]}
    chapter=${BASH_REMATCH[2]}
    

    捕获组是BASH_REMATCH 数组中的元素。元素 0 包含整个匹配项。

    此正则表达式将捕获第一个元素中的第一个点。第一个点之后的任何内容(包括后续点)都将位于第二个元素中。如果需要,可以轻松修改正则表达式以中断最后一个点。

    【讨论】:

      【解决方案3】:

      如果$arg 包含book.chap

      read BOOK CHAP<<<$(IFS="."; echo $arg)
      

      将相应地设置变量 BOOK 和 CHAP。这使用控制 bash 如何理解单词边界的 bash 内部字段分隔符 (IFS)。如果(比如说)您在原始 $arg 中有多个分隔符,那么只需指定更多变量来包含结果。

      来自here:

      $IFS 默认为空格(空格、制表符和换行符),但也可以是 更改,例如,解析逗号分隔的数据文件

      【讨论】:

      • IFS=. read -r book chapter &lt;&lt;&lt;"$1" 更干净。不需要echo 或命令替换。
      【解决方案4】:

      您可以使用括号来捕获这两个部分;之后,您可以使用反向引用再次获取它们。不同语言的语法不同;查看http://www.regular-expressions.info/brackets.html 了解关于一般反向引用的课程。

      【讨论】:

      • 感谢您的信息。是的,我已经在 Python 中完成了这种类型的分组正则表达式匹配,但我从未在 bash 脚本中使用过正则表达式。
      【解决方案5】:
      #!/bin/bash
      
      book=${1%.*}
      chapter=${1#*.}
      
      printf 'book: %s\nchapter: %s\n' "$book" "$chapter"
      

      【讨论】:

        【解决方案6】:

        Shell 参数扩展的模式替换

        有很多方法可以完成您想做的事情。其他答案未涵盖的一种方式是pattern substitution。

        如果您知道该值将始终在句点上正确拆分,则可以对该值应用模式替换,以便使用 IFS 轻松进行标记化。例如:

        set -- foo.bar
        myvar="${1/./ }"
        echo $myvar
        

        这将产生foo bar。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2019-03-03
          • 1970-01-01
          • 1970-01-01
          • 2012-03-03
          相关资源
          最近更新 更多