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

时间:2009-08-07 21:19:23

标签: regex bash shell

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

我想使用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 个答案:

答案 0 :(得分:27)

我很惊讶在这里看不到本地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]}中。

答案 1 :(得分:1)

如果您想在Bash中执行此操作,则可以执行以下操作。它使用globbing而不是regexp(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

答案 2 :(得分:1)

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

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

答案 3 :(得分:0)

取决于你想要对变量做什么

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

答案 4 :(得分:0)

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