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

我试图在我的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')

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

618836 次浏览
find "$directory" -type f -name "*.in"

比整个代码略短(而且更安全——处理文件名和目录名中的空白)。

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

  1. browsefolders ()后面少了一个{
  2. 所有$in都应该是$suffix
  3. cut的行只能得到front.middle.extension的中间部分。你应该阅读shell手册中的${varname%%pattern}和朋友。

我假设您将此作为shell脚本的练习,否则已经提出的find解决方案是可行的。

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

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

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

(少敲一次键)。

find {directory} -type f -name '*.extension'

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

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

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

find . -name 'pom.xml' -print
find $directory -type f -name "*.in"|grep $substring

不使用find:

du -a $directory | awk '{print $2}' | grep '\.in$'
for file in "${LOCATION_VAR}"/*.zip
do
echo "$file"
done

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

扩展选项是extglob,需要使用下面的shopt选项进行设置。该选项通过-s支持启用,并通过-u标志禁用。此外,你可以使用更多的选项,如nullglob,其中一个不匹配的glob被完全扫走,取而代之的是一组零字。和globstar,它允许递归遍历所有目录

shopt -s extglob nullglob globstar

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

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

fileList=(**/*.csv)

选项**是递归遍历子文件夹,而*.csv是glob展开,以包括上述扩展名的任何文件。现在打印实际文件,就这样做

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

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

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中运行的脚本的可移植性,那么这个选项是不正确的。

find "$PWD" -type f -name "*.in"