我见过有关如何迭代多个文件扩展名的各种主题,但在大多数情况下,列表是已定义的。
例子:
for file in ${arg}/**/*.{txt,h,py}
do
....
done
可以看出,.TXT
文件将被忽略。可悲的是,回答这个问题的人说它只适用于 bash4。但我的设置使用bash3.x。
关于如何做到这一点有什么想法吗?
答案1
您可以在其中bash
设置nocaseglob
:
shopt -s nocaseglob
for file in "$arg"/**/*.{txt,h,py}
do
....
done
shopt -u nocaseglob
noclaseglob
可以在bash
2.01 以后的任何版本中使用,但**
需要bash
4.0 或更高版本(并且它遵循符号链接,直到bash
4.3 已修复)。请注意对引号的更正,$arg
因为如果其中包含空格或通配符,则会出现问题。
不使用**
您可以执行以下操作:
find "$arg" \( -iname '*.txt' -o -iname '*.h' -o -iname '*.py' \) -exec bash -c '
for file; do
...
done' bash {} +
这将找到您正在查找的所有文件,并将它们作为单独的参数传递给新的 bash 实例,然后该实例将循环遍历它们。如果您的每个文件操作是单个命令,您可能可以跳过新的 bash 实例并直接使用该命令。
更新
根据下面 Stephane 的评论,POSIX 兼容的解决方案是:
find "$arg" \( -name '*.[tT][xX][tT]' -o -name '*.[hH]' -o -name '*.[pP][yY]' \) \
-exec sh -c '
for file do
...
done' sh {} +
答案2
改用zsh
:
setopt extendedglob
for f ($arg/**/*.(#i)(txt|h|py)(N.)) {
...
}
**/
:任何级别的子目录(#i)
是为 glob 的其余部分打开不区分大小写的匹配(如~(i)
)ksh93
。(N.)
是全局限定符。N
是如果没有匹配的文件则不返回错误并.
仅选择常规文件(相当于find
s-type f
))。您可以D
在其中添加一个来匹配点(隐藏)文件并进入隐藏目录(就像find
默认情况一样)。
答案3
一个简单的怎么样:
for file in "$(ls -1 | grep -iE '\.txt|\.py|\.h')";
do
....
done
另一个简单的选择是:
find . -maxdepth 1 -iname '*.txt'; find . -maxdepth 1 -iname '*.py'; find . -maxdepth 1 -iname '*.h';
您可以在 bash 中将 find 括在 $() 括号中以获得列表。