如何迭代多个文件扩展名而不关心大小写?

如何迭代多个文件扩展名而不关心大小写?

我见过有关如何迭代多个文件扩展名的各种主题,但在大多数情况下,列表是已定义的。

例子:

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可以在bash2.01 以后的任何版本中使用,但**需要bash4.0 或更高版本(并且它遵循符号链接,直到bash4.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是如果没有匹配的文件则不返回错误并.仅选择常规文件(相当于finds -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 括在 $() 括号中以获得列表。

相关内容