循环浏览具有特定扩展名的所有文件


109
for i in $(ls);do
    if [ $i = '*.java' ];then
        echo "I do something with the file $i"
    fi
done

我想循环浏览当前文件夹中的每个文件,并检查其是否与特定扩展名匹配。上面的代码不起作用,您知道为什么吗?


4
for i in $(ls *.java); do echo "do something with file $i"; done
发言人

没有办法解决该if语句?
AR89 2013年

1
您正在与$i文字字符串“ * .java” 进行比较;此处不执行图案扩展。
chepner

要使用它来修复if语句,请使用if [[ $i == *.java ]]; then..(请注意,双[[]]和双引号* .java)。
另一个人

2
不解析ls -接受@chepner的回答
glenn jackman

Answers:


201

无需花哨的技巧:

for i in *.java; do
    [ -f "$i" ] || break
    ...
done

警卫人员确保,如果没有匹配的文件,则循环将退出而不尝试处理不存在的文件名*.java。在bash(或支持类似功能的shell)中,您可以使用该nullglob选项来简单地忽略失败的匹配,而不输入循环的主体。

shopt -s nullglob
for i in *.java; do
    ...
done

5
最简单的方法是添加另一种模式:for i in *.java *.cpp; do。如果您在扩展模式的启用bashshopt -s extglob,你可以写for i in *.@(java|cpp); do
chepner,2015年

8
如果它实际上匹配任何文件,它将。您需要使用shopt -s nullglob非匹配模式扩展为空序列,而不是按字面意义对待。
chepner

1
@zygimantus是的,只要当前目录是运行脚本的位置,就应该这样做。如果您不在想要的目录中,则应cd在开始for循环之前进入该目录
danielsdesk

1
@puk取决于您的shell选项。默认情况下,不匹配的模式被视为文字字符串。您可以将nullglob其视为空序列,也failglob可以将其视为错误。(如果同时设置两者,failglob则优先。)
chepner

3
@chepner对于非专家来说,在答案中指出这一点可能很有用,因为有人可能会复制粘贴并将其发现不起作用。一个完美的例子是有人在执行关键功能之前将所有“ .jpg”文件转换为“ .png”
puk

13

正确答案是@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会怎么样?
AR89

13

递归添加子文件夹,

for i in `find . -name "*.java" -type f`; do
    echo "$i"
done

而不是find . -name "*.java" -type f -exec echo \{\} \; 避免对–umläute的输出进行错误的分析find
2015年

1
如果没有,至少应该"$i"在循环内引用。
Tripleee

2
如果任何文件名中都包含空格,则此操作将无效。
codeforester

1
@codeforester我确实遇到了这个问题,并使用此答案中的方法解决了这个问题:askubuntu.com/a/343753/551184
fsinisi90

7

循环通过与结尾的所有文件:.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

3

我同意关于循环浏览文件的正确方法的其他答案。然而,OP问:

上面的代码不起作用,您知道为什么吗?

是!

优秀的文章test和[和[[?]之间有什么区别?”详细说明了其他区别,您不能使用expression matchingpattern matchingtest命令内(这是的简写[

功能新测试[[旧测试[示例

模式匹配=(或==)(不可用)[[$ name = a *]] || echo“名称不以'a'开头:$ name”

正则表达式=〜(不可用)[[$(date)=〜^ Fri \ ... \ 13]] && echo“今天是13号星期五!”
匹配

因此,这就是脚本失败的原因。如果OP对使用[[语法的答案感兴趣(其缺点是无法在该[命令的多个平台上获得支持),那么我很乐意编辑答案以包括该答案。

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


2

正如@chepner在他的评论中所说,您正在将$ i与固定字符串进行比较。

要扩展和纠正这种情况,您应将[[]]与正则表达式运算符=〜一起使用

例如:

for i in $(ls);do
    if [[ $i =~ .*\.java$ ]];then
        echo "I want to do something with the file $i"
    fi
done

=〜右边的正则表达式是针对左手运算符的值进行测试的,不应使用引号引起来((引号不会出错,但会与固定字符串进行比较,因此很可能会失败”

但是上面使用glob的@chepner的答案是一种更为有效的机制。


用变量ext代替.java会怎么样?
AR89

1
ack,不需要正则表达式:if [[ $i == *.java ]]if [[ $i == *.$ext ]]。但是请不要解析ls
格伦

1

我发现此解决方案非常方便。它使用以下-or选项find

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

它会找到的文件扩展名为texpngpdf

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.