2016-04-26 98 views
0

上下文:我正在编写一个shell脚本来帮助管理以文本文件以人类可读方式存储并使用普通文本编辑器进行编辑的简单数据库。 (每个条目是一个文本文件,其名称是一个ID号,并且所有文件都存储在一个目录中。)POSIX正则表达式:仅在逗号分隔的项目内匹配

我目前的问题是搜索。有一些头文件,它们基本上是文件顶部的数据字段。例如,我们来看一下标记字段,该字段从Tags:\t(其中\t是一个字面制表符)开始,然后有一个逗号分隔标记列表。我希望能够将用户提供的正则表达式插入到对grep的更大调用中,并且只有在每个逗号分隔项内,用户的正则表达式匹配

下面是从我的文档有点描述,我想发生什么:


hregexes是仅在逗号分隔的项目匹配ERES。例如,对于首标Tags: foo, bar baz

REGEX  :: MATCHES? 
foo  :: yes 
bar  :: yes 
baz  :: yes 
az  :: yes 
.*baz  :: yes 
ba.*az :: yes 
o, ba  :: no 
foo.*baz :: no 

这将理想地纯粹工作与POSIX扩展正则表达式,用于与系统的其余部分的一致性;我有一个使用Python进行搜索的简化版本,但决定我应该重写那部分,以便系统不会搜索POSIX正则表达式和一些Python。

我确实试图想出一个模式,但是我用regexps来做一些复杂的事情还不够好。在以下尝试中,$2是我们正在查找的标题,并且$3是在该标题中匹配的模式。

grep -El "$2: (|.*,|.*,)[^,]*$3[^,]*(,|\b)" *.dre 

这不会错过它应该抓住任何结果,但它的问题在于o, bafoo.*baz都匹配时,他们不应该;在这一点上,我不妨只搜索$2: .*$3

如果这对于单个ERE来说是不可能的,那么在Bash中是否有另一种好方法呢?我的数据库已经有超过一千个文件,并且可以轻松增长到很多次,所以我不希望循环遍历每个文件,然后遍历逗号分隔列表中的每个项目,并且每次都会产生shell开销。

回答

1

以下解决方案基于佩里更换分离器的想法,并非万无一失,但保留了理想的运行时间,同时使其非常难以拧紧。

首先,我们选择一个分隔符来替换逗号;我选择了@@@@@,推理这不会发生在任何正确形成的标签。 (这种标签通常是纯字母。)

然后,我们修改用户的正则表达式与[^@]更换.,从而没有表达会越过边界@@@@@除非明确组成的。我可能会错过其他一些比赛,比如说[[:punct:]];我并不十分担心这些,但如果有人对其他特殊字符的想法可能有问题,我想听听他们的消息。

最后,我们创建一个包含所有Tags线流,编辑,使其包含只是文件名和新@ -delimited标签,用户的模式匹配应用到该流,然后删除一切,但在文件名比赛流。

最终代码:

header="$2" 
pattern=$(echo "$3" | sed -e 's/\./[^@]/') 
grep -m 1 "$header: " *.dre | sed -e "s/$header:  //" | \ 
    sed -e 's/, /@@@@@/g' | grep -E "$pattern" | \ 
    sed -e 's/\([0-9]\{5\}\.dre\):.*/\1/' 

[0-9]\{5\}\.dre是匹配所有合法文件名的表达式。)

输出示例:

00775.dre 
00787.dre 
00788.dre 
00883.dre 
00889.dre 

(显然,匹配可以被保存到可变的进一步处理;这就是我在这里做的。)

+0

我没有尝试,但它看起来像你在正确的轨道上。你也碰到了在纯shell中能够实现的限制,所以请记住,来自用户的下一个功能请求可能会促使你用更低级的语言编写一些帮助程序:) – Perry

1

诀窍是将逗号更改为更好的作为grep中的分隔符,即换行符。

head -1 $DATA_FILE | sed -E 's/,/\'$'\n/g' | grep -qE "$SEARCH" 

if [ $? == 0 ] 
then 
    echo "Pattern found: $DATA_FILE" 
else 
    echo "Pattern not found: $DATA_FILE" 
fi 

$DATA_FILE是包含标签的文件。 $SEARCH是正在寻找的正则表达式。

if声明显然会被适合您的应用程序的逻辑替代。

head命令从文件中提取第一行(“Tag:”行)。 sed命令用换行符替换该行上的所有逗号(在这一点上删除“Tag:”可能是明智的做法,以避免误报)。 grep然后只需搜索输入正则表达式的每一行结果集并返回一个状态,指示是否找到它。

搜索每个数据文件的最小数量。

+0

这个作品(除了'标签'不一定是第一行,所以我使用'grep -hm 1'标签:''),但它需要循环Bash中的目录中的每个文件,这已经减慢了搜索的速度因子为60,几乎从用户的角度瞬间变为几秒。 –

+0

我想我已经找到了一个可行的解决方案,我已经发布了一个答案;我很想听听你的想法。 –

相关问题