2014-11-05 35 views
2

假設你有一個文本文件行,說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函數的任何建議?

+0

'過濾器= $ *'沒有給你一個數組,並用空格混淆參數。不要這樣做。只需在'$ @「中使用'for filter; (甚至只是「過濾器;做」)循環所有參數。 – 2014-11-05 19:09:10

回答

2

如果您grep支持-P那麼你可以使用此功能:

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

filt 'dummy' '\d' 
dummy1 
dummy2 
dummy3 

filt 'foobar' 
foobar 
foobar.dummy 
foobar.dummy 

UPDATE:如果grep -P不可用,那麼你可以使用awk

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

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

filt 'foobar' 
foobar 
foobar.dummy 
foobar.dummy 
1

像這樣的東西應該工作:

對於bash可以通過更換

grep "$filter" | ad_hoc_show "[email protected]" 
以避免不必要的子炮彈:

#!/bin/sh 

ad_hoc_show() { 
    filter=$1 
    shift 

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

    grep "$filter" | ad_hoc_show "[email protected]" 
} 

file=$1 
shift 
ad_hoc_show "[email protected]" <"$file" 

正如David C.蘭在他的評論中指出,

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

在遞歸調用中。

通過使用"${@:2}" in the ad_hoc_show calls and removing the shift`行,您可以避免使用偏移數組索引(我不知道是否有官方術語)使用shift

+1

好的解決方案。您可以在函數中使用'ad_hoc_show「$ @」<「$ file」'和'ad_hoc_show「$ @」<<< $(grep「$ filter」)'來消除產卵子殼體。消除「移位」和用「$ {@:2}」索引參數索引的任何缺點「' – 2014-11-05 20:35:02

+0

@ DavidC.Rankin文件重定向是一個好主意。使用命令替換而不是管道是更可疑的,因爲'<<<'是一個bash-ism,並且我相信原來是'sh'安全的。除了我認爲更多人熟悉輪班之外,我不能想到不使用「」{$:2}「'來代替輪班的理由。 – 2014-11-05 20:53:06