循环遍历具有特定扩展名的所有文件

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。如果你在bashshopt -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 matchingpattern matching

功能新测试[[旧测试[示例 模式匹配 =(或 ==)(不可用)[[ $name = a* ]] || echo "名称不以 'a' 开头:$name" 正则表达式 =~(不可用)[[ $(date) =~ ^Fri\ ...\ 13 ]] && echo "今天是 13 号星期五!" 匹配

所以这就是你的脚本失败的原因。如果 OP 对使用 [[ 语法的答案感兴趣(缺点是在与 [ 命令一样多的平台上不受支持),我很乐意编辑我的答案以包含它。

编辑:有关如何将答案中的数据格式化为表格的任何提示都会有所帮助!

【讨论】:

【参考方案7】:

我发现这个解决方案非常方便。它使用find 中的-or 选项:

find . -name \*.tex -or -name "*.png" -or -name "*.pdf"

它将找到扩展名为texpngpdf的文件。

【讨论】:

以上是关于循环遍历具有特定扩展名的所有文件的主要内容,如果未能解决你的问题,请参考以下文章

遍历 QTreeView + QFileSystemModel 上具有所需文件扩展名的所有项目

powershell 递归删除具有特定扩展名的所有文件

在 Unix 中查找所有具有特定扩展名的文件?

inotify 是不是可以让我监视所有具有特定扩展名的文件,无论它们在磁盘上的啥位置?

如何删除具有特定扩展名的所有文件

python 查找具有特定扩展名的目录中的所有文件