![在 bash 或 zsh 中循环遍历一个文件扩展名或另一个文件扩展名](https://linux22.com/image/197201/%E5%9C%A8%20bash%20%E6%88%96%20zsh%20%E4%B8%AD%E5%BE%AA%E7%8E%AF%E9%81%8D%E5%8E%86%E4%B8%80%E4%B8%AA%E6%96%87%E4%BB%B6%E6%89%A9%E5%B1%95%E5%90%8D%E6%88%96%E5%8F%A6%E4%B8%80%E4%B8%AA%E6%96%87%E4%BB%B6%E6%89%A9%E5%B1%95%E5%90%8D.png)
这在语法上是正确的:
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
以及 zsh和KSH_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
但是,会按照区域设置中的顺序进行排序,其中.
在排序算法中首先会被忽略,这在当今很常见(如footb
或foott
之前footx
和之后foobw
)。