递归查找具有特定扩展名的文件
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
【讨论】:
虽然此代码可能会回答问题,但提供有关此代码为何和/或如何回答问题的额外上下文可提高其长期价值。以上是关于递归查找具有特定扩展名的文件的主要内容,如果未能解决你的问题,请参考以下文章