代码之家  ›  专栏  ›  技术社区  ›  foobarfuzzbizz

如何将正则表达式的匹配项赋给变量?

  •  15
  • foobarfuzzbizz  · 技术社区  · 15 年前

    我有一个文本文件,里面有各种条目。每个条目以包含所有星号的行结尾。

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

    下面是一个示例输入文件:

    ***********
    Field1
    ***********
    Lorem ipsum
    Data to match
    ***********
    More data
    Still more data
    ***********
    

    以下是迄今为止我的解决方案:

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

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

    5 回复  |  直到 15 年前
        1
  •  24
  •   Cascabel    15 年前

    我很惊讶这里没有本地的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
    

    重要的一点是扩展测试 [[ ... ]] 使用它的regex比较 =~ 将整个匹配存储在 ${BASH_REMATCH[0]} 捕获的火柴 ${BASH_REMATCH[i]} .

        2
  •  1
  •   Jukka Matilainen    15 年前

    如果你想在bash中完成它,你可以做如下的事情。它使用globbing而不是regexps 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
    
        3
  •  1
  •   Brad Gilbert    15 年前

    尝试在命令周围加双引号。

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

    取决于你想对变量做什么

    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中以备以后使用…例如array[++d]=s

        5
  •  0
  •   Brad Gilbert    15 年前

    在(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
    

    这将提供以下输出:

    record start:
    this is a 2-line
    record
    
    record end
    record start:
    
    the 2nd record
    is 3 lines
    long
    
    record end
    record start:
    
    a 3rd * record
    
    record end