Bash中有多个多行正则表达式匹配

时间:2010-01-22 15:06:49

标签: regex bash

我正在尝试在bash脚本中进行一些相当简单的字符串解析。 基本上,我有一个由多个多行字段组成的文件。每个字段都由一个已知​​的页眉和页脚包围。

我想将每个字段分别提取到数组或类似字符中,如此

>FILE=`cat file`
>REGEX="@#@#@#[\s\S]+?@#@#@"
> 
>if [[$FILE =~ $REGEX ]] then
>   echo $BASH_REMATCH
>fi

文件:

@#@#@#################################
this is field one
@#@#@#
@#@#@#################################
this is field two
they can be any number of lines
@#@#@#

现在我很确定问题是bash与“。”

的新行不匹配

我可以将它与“pcregrep -M”匹配,但当然整个文件将匹配。我可以一次从pcregrep获得一场比赛吗?

我并不反对使用某些内联perl或类似内容。

提前致谢

4 个答案:

答案 0 :(得分:3)

如果你有傻瓜

awk 'BEGIN{ RS="@#*#" }
NF{
    gsub("\n"," ") #remove this is you want to retain new lines
    print "-->"$0 
    # put to array
    arr[++d]=$0
} ' file

输出

$ ./shell.sh
--> this is field one
--> this is field two they can be any number of lines

答案 1 :(得分:1)

TXR语言执行全文档多行匹配,绑定变量,以及(使用-B“dump bindings”选项)发出适当的转义shell变量赋值,可以是{{1} } -ed。支持数组。

eval字符是特殊的,所以它必须加倍才能字面匹配。

@

$ cat fields.txr @(collect) @@#@@#@@################################# @ (collect) @field @ (until) @@#@@#@@# @ (end) @ (cat field)@# <- catenate the fields together with a space separator by default @(end) $ txr -B fields.txr data field[0]="this is field one" field[1]="this is field two they can be any number of lines" $ eval $(txr -B fields.txr data) $ echo ${field[0]} this is field one $ echo ${field[1]} this is field two they can be any number of lines 语法匹配整行。这些被收集到列表中,因为它位于@field内,并且列表被收集到列表列表中,因为它嵌套在另一个@(collect)中。然而,内部@(collect)将内部列表减少为单个字符串,因此我们最终得到一个字符串列表。

这是“经典TXR”:它最初是如何设计和使用的,是由这个想法引发的:

  

为什么我们不在这里 - 文件向后工作并从大量文本解析为变量?

默认情况下,默认情况下,在shell语法中,默认情况下,匹配变量的隐式发送仍然是受支持的行为,即使语言变得更加强大,因此不需要与shell脚本集成。

答案 2 :(得分:0)

我会围绕awk建立一些东西。这是第一个概念证明:

awk '
    BEGIN{ f=0; fi="" }
    /^@#@#@#################################$/{ f=1 }
    /^@#@#@#$/{ f=0; print"Field:"fi; fi="" }
    { if(f==2)fi=fi"-"$0; if(f==1)f++ }
' file

答案 3 :(得分:0)

begin="@#@#@#################################"
end="@#@#@#"
i=0
flag=0

while read -r line
do
    case $line in
        $begin)
            flag=1;;
        $end)
            ((i++))
            flag=0;;
        *)
            if [[ $flag == 1 ]]
            then
                array[i]+="$line"$'\n'    # retain the newline
            fi;;
     esac
done < datafile

如果要将标记线保留在数组元素中,请将赋值语句(带有标记测试)移到while之前case循环的顶部。