2014-12-29 22 views
0

在通用的shell脚本中,我想使用shell模式匹配来过滤文本文件的行。如何从shell中使用fnmatch?

我有文件名列表中files.txt:

file1.txt 
file2.sh 
file3.png 

而且我有图案patterns.txt列表:

other_file.txt 
file2.* 

如果我不得不在图案的正则表达式.txt,我可以这样做:

$ grep -v -f patterns.txt files.txt 

但我想使用shell globbing模式。我发现了C函数fnmatch,但没有shell/unix命令来使用它。

+0

这可以在shell中完成,但它会变成* slooow *。我建议你使用不同的语言。 –

+0

你能简单地将你的shell表达式翻译成正则表达式吗?即使自动化翻译的基本版本可能比替代方案更好。 –

+0

我希望我只是错过了像grep这样的与globs配合使用的命令。翻译模式也不是微不足道的。 – maikel

回答

0

确定,这将是真正unperformant,如POSIX SH甚至没有数组(我会用来缓存模式):

while IFS= read -r filename; do 
    hasmatch=0 
    while IFS= read -r pattern; do 
     case $filename in ($pattern) hasmatch=1; break ;; esac 
    done <patterns.txt 
    test $hasmatch = 1 || printf '%s\n' "$filename" 
done <files.txt 

如果您不需要的位置参数($1$2 ......),你可以尽管滥用那些模式缓存:

saveIFS=$IFS; IFS=' 
'; set -o noglob 
set -- $(cat patterns.txt) 
IFS=$saveIFS; set +o noglob 
while IFS= read -r filename; do 
    hasmatch=0 
    for pattern in "[email protected]"; do 
     case $filename in ($pattern) hasmatch=1; break ;; esac 
    done 
    test $hasmatch = 1 || printf '%s\n' "$filename" 
done <files.txt 

要小心空白,虽然存在:我们设置IFS以面值换行符,没有别的,即IFS='输入'

我已经测试了这个数据集加了几个附加项(比如a b*模式,测试空白行为),它似乎对我来说是根据OP中的规范工作的。

+0

你可以在'$ @'''中写'for pattern'而不是'for pattern。 –

+0

@AlexShpilkin只有在'pattern'之后有一个换行符而不是分号,因为它被某些shell错误分隔(参见GNU Autoconf手册,Portable Shell章节),它也是坏样式(旧且不一致),因此不推荐使用对于现代的外壳(除了由于上述不好的建议)。 - 完全披露:我是这些现代炮弹的作者之一。 – mirabilos