循环遍历具有特定扩展名的所有文件
Posted
技术标签:
【中文标题】循环遍历具有特定扩展名的所有文件【英文标题】:Loop through all the files with a specific extension 【发布时间】:2013-01-08 10:15:48 【问题描述】:for i in $(ls);do
if [ $i = '*.java' ];then
echo "I do something with the file $i"
fi
done
我想遍历当前文件夹中的每个文件并检查它是否与特定扩展名匹配。上面的代码不起作用,你知道为什么吗?
【问题讨论】:
for i in $(ls *.java); do echo "do something with file $i"; done
呢?
没有办法解决这个 if 语句?
您将$i
与文字字符串“*.java”进行比较;此处不进行模式扩展。
要修复 if 语句,请使用 if [[ $i == *.java ]]; then
..(注意双 [[]] 和未引用的 *.java)。
Don't parse ls
-- 接受@chepner 的回答
【参考方案1】:
不需要花哨的技巧:
for i in *.java; do
[ -f "$i" ] || break
...
done
守卫确保如果没有匹配的文件,循环将退出而不尝试处理不存在的文件名*.java
。在bash
(或支持类似功能的shell)中,您可以使用nullglob
选项
简单地忽略失败的匹配并且不进入循环体。
shopt -s nullglob
for i in *.java; do
...
done
【讨论】:
最简单的方法是添加另一个模式:for i in *.java *.cpp; do
。如果你在bash
和shopt -s extglob
中启用了扩展模式,你可以写for i in *.@(java|cpp); do
。
如果它实际上匹配任何文件,它会。您需要使用shopt -s nullglob
以便将不匹配的模式扩展为空序列,而不是按字面意思对待。
@chepner 对于非专家来说,在答案中指出这一点可能很有用,因为有人可能会复制粘贴它并发现它不起作用。一个完美的例子是在执行关键功能之前将所有“.jpg”文件转换为“.png”
我们需要[ -f "$i" ] || continue
,而不是[ -f "$i" ] || break
,对吧?
@codeforester 是对的,continue
是必要的。如果有一个名为b.java
的普通文件和一个名为a.java
的目录,那么循环可以在到达b.java
之前被break
终止。【参考方案2】:
递归添加子文件夹,
for i in `find . -name "*.java" -type f`; do
echo "$i"
done
【讨论】:
而不是find . -name "*.java" -type f -exec echo \\ \;
以避免错误解析find
的输出
如果你不这样做,至少你应该在循环中引用"$i"
。
如果任何文件的名称中有空格,这将不起作用。
@codeforester 我确实遇到了这个问题,我已经使用这个答案中的方法修复了它:askubuntu.com/a/343753/551184【参考方案3】:
正确答案是@chepner 的
EXT=java
for i in *.$EXT; do
...
done
但是,这里有一个小技巧可以检查文件名是否具有给定的扩展名:
EXT=java
for i in *; do
if [ "$i" != "$i%.$EXT" ];then
echo "I do something with the file $i"
fi
done
【讨论】:
使用变量ext
而不是 .java
会怎么样?【参考方案4】:
遍历所有以:.img
、.bin
、.txt
后缀结尾的文件,并打印文件名:
for i in *.img *.bin *.txt;
do
echo "$i"
done
或者以递归方式(在所有子目录中也可以找到):
for i in `find . -type f -name "*.img" -o -name "*.bin" -o -name "*.txt"`;
do
echo "$i"
done
【讨论】:
根据man find
:-o (meaning logical OR)
我喜欢您的最佳解决方案并对其表示赞同,但如果我没有具有该特定扩展名的文件,则会出现错误。如果找不到扩展,我可以做些什么来忽略扩展?【参考方案5】:
正如@chepner 在他的评论中所说,您正在将 $i 与固定字符串进行比较。
要扩展和纠正这种情况,您应该将 [[ ]] 与正则表达式运算符一起使用 =~
例如:
for i in $(ls);do
if [[ $i =~ .*\.java$ ]];then
echo "I want to do something with the file $i"
fi
done
=~ 右侧的正则表达式是针对左侧运算符的值进行测试的,不应被引用,( 引用不会出错,但会与固定字符串进行比较,因此很可能会失败"
但@chepner 上面使用 glob 的回答是一种更有效的机制。
【讨论】:
使用变量ext
而不是 .java
会怎么样?
确认,不需要正则表达式:if [[ $i == *.java ]]
或 if [[ $i == *.$ext ]]
。但是don't parse ls
一个漂亮的解决方案,因为我可以通过简单地使用for i in $(ls -lR); do ...
来在子目录中进行搜索,或者如果你想要文件的相对路径:for i in $(find -L .);do ...
借助另一个好的答案:@ 987654322@【参考方案6】:
我同意其他有关循环文件的正确方法的答案。然而,OP问:
上面的代码不起作用,你知道为什么吗?
是的!
一篇出色的文章 What is the difference between test, [ and [[ ?] 详细解释了除其他差异外,您不能在test
命令([
的简写)中使用expression matching
或pattern matching
所以这就是你的脚本失败的原因。如果 OP 对使用 [[
语法的答案感兴趣(缺点是在与 [
命令一样多的平台上不受支持),我很乐意编辑我的答案以包含它。
编辑:有关如何将答案中的数据格式化为表格的任何提示都会有所帮助!
【讨论】:
【参考方案7】:我发现这个解决方案非常方便。它使用find
中的-or
选项:
find . -name \*.tex -or -name "*.png" -or -name "*.pdf"
它将找到扩展名为tex
、png
和pdf
的文件。
【讨论】:
以上是关于循环遍历具有特定扩展名的所有文件的主要内容,如果未能解决你的问题,请参考以下文章
遍历 QTreeView + QFileSystemModel 上具有所需文件扩展名的所有项目