递归查找具有特定扩展名的文件

Posted

技术标签:

【中文标题】递归查找具有特定扩展名的文件【英文标题】:Recursively look for files with a specific extension 【发布时间】:2011-08-21 02:33:10 【问题描述】:

我正在尝试使用我的 bash(最新的 Ubuntu LTS 版本)在一个目录及其子目录中查找所有具有特定扩展名的文件。

这是写在脚本文件中的内容:

#!/bin/bash

directory="/home/flip/Desktop"
suffix="in"

browsefolders ()
  for i in "$1"/*; 
  do
    echo "dir :$directory"
    echo "filename: $i"
    #   echo $i#*.
    extension=`echo "$i" | cut -d'.' -f2`
    echo "Erweiterung $extension"
    if     [ -f "$i" ]; then        

        if [ $extension == $suffix ]; then
            echo "$i ends with $in"

        else
            echo "$i does NOT end with $in"
        fi
    elif [ -d "$i" ]; then  
    browsefolders "$i"
    fi
  done

browsefolders  "$directory"

不幸的是,当我在终端启动这个脚本时,它说:

[: 29: in: unexpected operator

(用$extension 代替'in'

这里发生了什么,错误在哪里? 但是这个花括号

【问题讨论】:

错误是由于缺少'' 这个问题与How can I recursively find all files in current and subfolders based on wildcard matching?重复 【参考方案1】:
find $directory -type f -name "*.in"

比整个东西短一点(而且更安全 - 处理文件名和目录名中的空格)。

对于名称中没有. 的条目,您的脚本可能会失败,从而使$extension 为空。

【讨论】:

是的,find 默认是递归的。您可以根据需要限制深度(参见手册页)。 我想将所有找到的文件作为参数传递给 jar 文件。如何执行此操作? @flip:这是一个不同的问题。发布一个新问题,详细说明您想做什么以及到目前为止您已经尝试过什么。 一点更正:使用 '*.in' 或 \*.in 而不是 "*.in" 因为双引号不会阻止 shell 扩展。 IE。如果当前目录中有扩展名为 .in 的文件,您的脚本将无法正常运行。 @Shnatsel:双引号确实可以防止外壳扩展。试试看。【参考方案2】:
find directory -type f -name '*.extension'

示例:要查找当前目录及其子目录中的所有csv 文件,请使用:

find . -type f -name '*.csv'

【讨论】:

【参考方案3】:

我使用的语法与@Matt 建议的有点不同:

find $directory -type f -name \*.in

(少了一次按键)。

【讨论】:

如果当前目录中有扩展名为 .in 的文件,Matt 的脚本也将无法运行,而您的脚本仍然可以运行。见***.com/questions/5927369/… @Shnatsel 这个评论(以及你的评论)是完全错误的。 @gniourf_gniourf 你应该为你的陈述提供一些参考,否则人们可能会简单地争论:“不,你错了”。但事实上你是对的:gnu.org/software/bash/manual/html_node/Double-Quotes.html @user1885518:我认为应该是声称脚本不起作用的人应该提供一些脚本失败的示例。这就是我将 cmets 留在有损坏脚本的地方时所做的事情:它通常是关于包含空格、换行符、glob 等的引号和文件名,我特别解释了它为什么会损坏。 在讨论中提供参考总是一个好方法,它不取决于谁是第一个。他应该,你应该。【参考方案4】:

不使用find

du -a $directory | awk 'print $2' | grep '\.in$'

【讨论】:

grep 在这里并不是必需的。 awk 具有正则表达式,可以将其输出限制为匹配模式的值。 如果您要处理 100 TB 的数据,此方法非常有用。查找命令需要太多时间来处理。这会立即开始。 awk|grep 是一种反模式。让 awk 做 grepping。【参考方案5】:
find "$PWD" -type f -name "*.in"

【讨论】:

【参考方案6】:
    browsefolders () 之后缺少一个 所有$in 都应该是$suffix 带有cut 的行只获取front.middle.extension 的中间部分。你应该在 $varname%%pattern 和朋友上阅读你的 shell 手册。

我假设您这样做是为了练习 shell 脚本,否则已经提出的 find 解决方案是可行的方法。

要在不运行脚本的情况下检查正确的 shell 语法,请使用 sh -n scriptname

【讨论】:

【参考方案7】:

虽然在这里使用find 命令可能很有用,但shell 本身提供了实现此要求的选项,而无需任何第三方工具。 bash shell 提供了一个扩展的 glob 支持选项,您可以使用它在与您想要的扩展名匹配的递归路径下获取文件名。

扩展选项为extglob,需要使用shopt 选项进行设置,如下所示。通过-s 支持启用这些选项,并通过-u 标志禁用这些选项。此外,您可以更多地使用几个选项,即nullglob,其中一个不匹配的 glob 被完全扫除,替换为一组零词。而globstar 允许递归遍历所有目录

shopt -s extglob nullglob globstar

现在您需要做的就是形成 glob 表达式以包含某个扩展名的文件,您可以如下所示进行操作。我们使用一个数组来填充 glob 结果,因为当正确引用和扩展时,带有特殊字符的文件名将保持不变,并且不会由于 shell 的分词而被破坏。

例如列出递归路径中的所有*.csv文件

fileList=(**/*.csv)

选项** 是通过子文件夹递归,*.csv 是全局扩展以包含所提到的任何扩展文件。现在要打印实际文件,只需执行

printf '%s\n' "$fileList[@]"

在 shell 脚本中使用数组并进行适当的引用扩展是正确的方法,但对于交互式使用,您可以简单地使用 ls 和 glob 表达式作为

ls -1 -- **/*.csv

这可以很好地扩展以匹配多个文件,即以多个扩展名结尾的文件(即类似于在find 命令中添加多个标志)。例如,考虑需要获取所有递归图像文件的情况,即扩展名*.gif*.png*.jpg,您所需要的只是

ls -1 -- **/+(*.jpg|*.gif|*.png)

这也可以很好地扩展到否定结果。使用相同的语法,可以使用 glob 的结果来排除某种类型的文件。假设您要排除具有上述扩展名的文件名,您可以这样做

excludeResults=()
excludeResults=(**/!(*.jpg|*.gif|*.png))
printf '%s\n' "$excludeResults[@]"

!() 构造是一个否定操作,不包括其中列出的任何文件扩展名,| 是一个交替运算符,就像在扩展正则表达式库中用于对 glob 进行 OR 匹配一样。

请注意,这些扩展的 glob 支持在 POSIX bourne shell 中不可用,它完全特定于 bash 的最新版本。因此,如果您正在考虑跨 POSIX 和 bash shell 运行的脚本的可移植性,则此选项不正确。

【讨论】:

【参考方案8】:

要在当前目录中查找所有pom.xml 文件并打印它们,您可以使用:

find . -name 'pom.xml' -print

【讨论】:

【参考方案9】:
find $directory -type f -name "*.in"|grep $substring

【讨论】:

【参考方案10】:
for file in "$LOCATION_VAR"/*.zip
do
  echo "$file"
done 

【讨论】:

虽然此代码可能会回答问题,但提供有关此代码为何和/或如何回答问题的额外上下文可提高其长期价值。

以上是关于递归查找具有特定扩展名的文件的主要内容,如果未能解决你的问题,请参考以下文章

使用rsync递归地只复制具有特定扩展名的文件

在文件夹中查找具有特定扩展名的文件

查找具有特定名称和任何扩展名的文件

如何从数组中查找具有特定扩展名的文件列表

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

linux 上查找包含特定文本的所有文件