如何使用过滤器链过滤行

时间:2014-11-05 19:06:45

标签: linux bash

假设你有一个文本文件,比如list.txt,就像这样:

# Category 1
foobar

# Category 2
dummy1
dummy2
dummy3

# Category 3
foobar.dummy
foobar.dummy

你有一个bash脚本,比如list.sh,从list.txt中提取行。该脚本使用一个或多个模式来使用grep过滤文本文件。从概念上讲,它将来自命令行:

cat list.txt | grep filter1 | grep fitler1 | ... | grep filtern

但是,问题是过滤器的数量会有所不同,因此您必须使用循环来进行过滤。对于循环,我希望像下面这样的东西可以工作。

filters=$*
for filter in ${filters[@]}; do
    result=`ad_hoc_show $result | grep $filter`
done

ad_hoc_show $result # should maintain original line structure

例如,下面是所需的输出。

$ list.sh foobar
foobar
foobar.dummy
foobar.dummy

$ list.sh dummy \d
dummy1
dummy2
dummy3

那么,关于如何实现ad_hoc_show函数的任何建议?

2 个答案:

答案 0 :(得分:2)

如果您的grep支持-P,那么您可以使用此功能:

filt() {
   re=$(printf "(?=.*?%s)" "$@")
   grep -P "$re" list.txt
}

filt 'dummy' '\d'
dummy1
dummy2
dummy3

filt 'foobar'
foobar
foobar.dummy
foobar.dummy

更新:如果grep -P不可用,您可以使用awk

filt() { re=$(printf "/%s/&&" "$@"); awk "${re:0: -2}" list.txt; }

filt 'dummy' '[0-9]'
dummy1
dummy2
dummy3

filt 'foobar'
foobar
foobar.dummy
foobar.dummy

答案 1 :(得分:1)

这样的事情应该有效:

#!/bin/sh

ad_hoc_show() {
    filter=$1
    shift

    if [ $# -eq 0 ]; then
        grep "$filter"
        return
    fi

    grep "$filter" | ad_hoc_show "$@"
}

file=$1
shift
ad_hoc_show "$@" <"$file"

David C. Rankin在评论中指出:

对于bash,可以通过替换

来避免不必要的子shell
grep "$filter" | ad_hoc_show "$@"

ad_hoc_show "$@" <<<"$(grep "$filter")"

在递归调用中。

使用shift ad_hoc_show {{1},您可以避免使用偏移数组索引来使用"${@:2}" in the(我不知道这是否有正式术语) } shift` lines。