如何从shell使用fnmatch? [英] How to use fnmatch from a shell?
问题描述
在通用的shell脚本中,我想使用shell模式匹配来过滤文本文件的行.
In a generic shell script, I would like to use shell pattern matching to filter the lines of a text file.
我在files.txt中有一个文件名列表:
I have a list of file names in files.txt:
file1.txt
file2.sh
file3.png
我在patterns.txt中有一个模式列表:
And I have a list of patterns in patterns.txt:
other_file.txt
file2.*
如果我在patterns.txt中有正则表达式,我可以这样做:
If I would have regular expressions in patterns.txt, I could do this:
$ grep -v -f patterns.txt files.txt
但是我想使用Shell Globing模式.我找到了C函数fnmatch,但没有使用它的shell/unix命令.
But I would like to use shell globbing patterns. I found the C function fnmatch but no shell/unix command to use it.
推荐答案
好的,这真的很糟糕,因为POSIX sh甚至没有数组(我本该用于缓存模式):
OK, this is going to be really unperformant, as POSIX sh does not even have arrays (which I would have used for caching the patterns):
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
,...),则可以通过以下方式将其用于模式缓存:
If you don’t need the positional arguments ($1
, $2
, …) you can abuse those for pattern caching though:
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 "$@"; do
case $filename in ($pattern) hasmatch=1; break ;; esac
done
test $hasmatch = 1 || printf '%s\n' "$filename"
done <files.txt
但是请注意其中的空白:我们将IFS
设置为文字换行符,而没有其他设置,即IFS='
Enter '
.
Be careful about whitespace there though: we set IFS
to a literal newline character and nothing else, i.e. IFS='
Enter'
.
我已经使用您的数据集对它进行了测试,并添加了一些附加内容(例如a b*
模式,以测试空白行为),并且根据OP中的规范,它似乎对我有用.
I’ve tested this with your dataset plus a few additions (like a a b*
pattern, to test whitespace behaviour), and it seems to work for me according to the spec in the OP.
这篇关于如何从shell使用fnmatch?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!