在 bash 或 zsh 中循环遍历一个文件扩展名或另一个文件扩展名

在 bash 或 zsh 中循环遍历一个文件扩展名或另一个文件扩展名

这在语法上是正确的:

for f in *bw;do echo $f;done

但是我如何添加一个扩展来循环其中一个?

  • 以下不起作用:
    for f in *bw|*txt;do echo $f;done
    
  • 这也不起作用:
    for f in *bw or *txt;do echo $f;done
    

答案1

你不知道。你迭代一遍两个都“扩展”并(如果需要)检查其中一个或两个是否存在。例如,如果您只想打印一个或另一个(看到的第一个),请保留每个文件的基本名称(不带扩展名)的列表 - 关联数组对此很有用,因为它很容易查找。例如在 bash 中:

declare -A files

for f in *.bw *.txt; do
  bn=${f%.*}
  if [ -z "${files[$bn]}" ] ; then
    echo "$f"
    files["$bn"]=1
  fi
done

答案2

在重击中shopt -s extglob以及 zshKSH_GLOB启用:

for f in *.@(bw|txt)

请注意,在 bash 中,如果没有匹配项,则循环将运行并$f设置为文字字符串*.@(bw|txt)。为了避免这种情况,在 bash 中:

shopt -s nullglob
for f in *.@(bw|txt)

在 zsh 中,默认情况下,如果没有匹配项,您将收到错误消息。为了避免这种情况,请添加N 全局限定符

for f in *.@(bw|txt)(N)

在zsh中,有一个更简单的解决方案,可以使用默认选项,(N)如果没有匹配项,则不执行任何操作:

for f in *.(bw|txt)(N)

所有这些都将按字母顺序对所有条目进行排序,两个扩展名混合的文件(也就是说,仅扩展名不同的重复名称将(可能)是连续的)。您可以根据需要在括号内列出尽可能多的以竖线分隔的模式条目,并且它们可以包含更多的通配符(例如(zip|tar.?z))。


1foo.bw foot.bw foot.txt foo.txt但是,会按照区域设置中的顺序进行排序,其中.在排序算法中首先会被忽略,这在当今很常见(如footbfoott之前footx和之后foobw)。

相关内容