【问题标题】:How can I assign the match of my regular expression to a variable?如何将正则表达式的匹配项分配给变量?
【发布时间】:2010-11-17 20:07:40
【问题描述】:

我有一个包含各种条目的文本文件。每个条目都以包含所有星号的行结束。

我想使用 shell 命令来解析这个文件并将每个条目分配给一个变量。我该怎么做?

这是一个示例输入文件:

*********** 字段1 *********** Lorem ipsum 匹配的数据 *********** 更多数据 还有更多数据 ***********

到目前为止,我的解决方案如下所示:

#!/bin/bash
for error in `python example.py | sed -n '/.*/,/^\**$/p'`
do
    echo -e $error
    echo -e "\n"
done

但是,这只是将匹配文本中的每个单词分配给 $error,而不是整个块。

【问题讨论】:

    标签: regex bash shell


    【解决方案1】:

    在 (ba)sh 中拆分记录并不是那么容易,但可以使用 IFS 拆分单个字符(只需在 for 循环之前设置 IFS='*' ,但这会生成多个空记录,如果有的话会出现问题记录包含一个'*')。显而易见的解决方案是使用 perl 或 awk 并使用 RS 来拆分记录,因为这些工具提供了更好的拆分记录机制。混合解决方案是使用 perl 进行记录拆分,并让 perl 使用您想要的记录调用您的 bash 函数。例如:

    #!/bin/bash
    
    foo() {
        echo record start:
        echo "$@"
        echo record end
    }
    export -f foo
    
    perl -e "$/='********'; while(<>){chomp;system( \"foo '\$_'\" )}" << 'EOF'
    this is a 2-line
    record
    ********
    the 2nd record
    is 3 lines
    long
    ********
    a 3rd * record
    EOF
    

    这给出了以下输出:

    记录开始: 这是 2 行 记录 记录结束 记录开始: 第二条记录 是 3 行 长 记录结束 记录开始: 第三条 * 记录 记录结束

    【讨论】:

    • 请注意,这里给出的脚本几乎肯定需要 /bin/sh 为 bash。
    【解决方案2】:

    我很惊讶在这里没有看到原生 bash 解决方案。是的,bash 有正则表达式。您可以在线找到大量随机文档,特别是如果您在查询中包含“bash_rematch”,或者只是查看手册页。这是一个愚蠢的例子,取自 here 并稍作修改,打印整个匹配,以及每个捕获的匹配,用于正则表达式。

    if [[ $str =~ $regex ]]; then
        echo "$str matches"
        echo "matching substring: ${BASH_REMATCH[0]}"
        i=1
        n=${#BASH_REMATCH[*]}
        while [[ $i -lt $n ]]
        do
            echo "  capture[$i]: ${BASH_REMATCH[$i]}"
            let i++
        done
    else
        echo "$str does not match"
    fi
    

    重要的是,扩展测试 [[ ... ]] 使用其正则表达式比较 =~ 将整个匹配存储在 ${BASH_REMATCH[0]} 中,并将捕获的匹配存储在 ${BASH_REMATCH[i]} 中。

    【讨论】:

    • 确实,如果有一个明确的 bash 正则表达式指南会很好,但就像@Jefromi 所说,这只是一堆随机性。
    • @Noah:来自手册页:“运算符右侧的字符串被视为扩展正则表达式并进行相应匹配(如 regex(3)。”所以它是 POSIX 扩展正则表达式,是的? 这似乎...相当确定。
    • 这一切都很好,杰弗罗米。但它不是diveintobashregex.org
    • @Noah:可以说问题在于谷歌的排名,而不是文档的存在。该信息存在于多个位置,只是不在顶部显示“bash”并使其成为“bash 正则表达式”等查询的顶部结果的页面上。
    【解决方案3】:

    尝试在命令两边加上双引号。

    #!/bin/bash
    for error in "`python example.py | sed -n '/.*/,/^\**$/p'`"
    do
        echo -e $error
        echo -e "\n"
    done
    

    【讨论】:

      【解决方案4】:

      如果您想在 Bash 中执行此操作,您可以执行以下操作。它使用通配符而不是正则表达式(extglob shell 选项启用扩展模式匹配,因此我们可以匹配仅由星号组成的行。)

      #!/bin/bash
      shopt -s extglob
      entry=""
      while read line
      do
          case $line in 
              +(\*))
                  # do something with $entry here
                  entry=""
                  ;;
              *)
                  entry="$entry$line
      "
                  ;;
          esac
      done
      

      【讨论】:

        【解决方案5】:

        取决于你想对变量做什么

        awk '
        f && /\*/{print "variable:"s;f=0}
        /\*/{ f=1 ;s="";next}
        f{
           s=s" "$0
        }' file
        

        输出:

        # ./test.sh
        variable: Field1
        variable: Lorem ipsum Data to match
        variable: More data Still more data
        

        上面只是将它们打印出来。如果需要,可以存储在数组中以备后用...例如 array[++d]=s

        【讨论】:

          猜你喜欢
          • 2014-07-20
          • 1970-01-01
          • 2013-01-20
          • 1970-01-01
          • 2015-07-06
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-10-26
          相关资源
          最近更新 更多