使用Shell脚本查找特定文件类型的文件

3

我有一个要求,需要递归循环遍历目录中所有特定文件类型的文件。文件类型是一个包含我们需要处理的文件类型列表的数组变量。数组值实际上是动态生成的。为了简单起见,我声明了一个静态数组。

 declare -a arr=("pdf" "doc" "txt")

我有以下代码来递归列出目录中的所有文件,但我无法弄清楚如何包含数组“arr”,以仅返回包含在数组中的文件类型。
find $i -type f -print0 | while read -d $'\0' file; do
    echo $file;
    #Process file
done

请帮我修改代码,以便只检索指定文件类型,而不是所有文件。


这个Superuser SE网站上的这个问题可能会有所帮助。 - Mike Holt
2个回答

5
我认为你所说的文件类型 "pdf"、"doc"、"txt",指的是带有这些扩展名的文件名。
如果文件类型数量比较少(不超过几十个),那么你可以构建一个参数数组以传递给 find 命令,格式如下:
... -name '*.pdf' -o -name '*.doc' -o -name '*.txt' ...

假设文件类型的数组不为空,这是一种方法(感谢@mike-holt):
arr=(pdf doc txt)

findargs=()

for t in "${arr[@]}"; do
    findargs+=(-name "*.$t" -o)
done

find . -type f \( "${findargs[@]}" -false \)

我也喜欢那种方式。 - David C. Rankin

4
你需要做的是根据你的类型数组(假设是扩展名)动态构建一个正则表达式,并将其传递给带有 -regex 选项的 find 命令。然后,find 可以使用该正则表达式来查找匹配的文件名。根据你的示例,你想要构建一个类似于以下的正则表达式:
"^.*[.]\(pdf\|doc\|txt\)$"

为了从数组内容动态构建正则表达式,您可以执行类似以下操作的方式。
#!/bin/bash

arr=(pdf doc txt)   ## dynamically built array of extensions
n=${#arr[@]}        ## number of elements in array
regex='^.*[.]\('    ## beginning of regex
srch="${1:-.}"      ## path to search (default '.')

for ((i = 0; i < $n; i++)); do  ## loop over each element
    ## if not last, add "${arr[i]}\|" otherwise add "${arr[i]}\)"
    ((i < n - 1)) && regex="$regex${arr[i]}\|" || regex="$regex${arr[i]}\)"
done

regex="$regex\$"    ## add the final '$'

find "$srch" -type f -regex "$regex"  ## execute the find

注意,这里使用了基于Bash的C风格循环和数组,因此它不是POSIX shell可移植的——但由于您使用的是一个数组,这不应该是一个问题)

试试看,让我知道是否符合您的需求。


1
或者你可以直接执行 find \( $(printf -- "-name *.%s -o " "${arr[@]}") -false \) - Mike Holt
1
是的,这看起来像是一种更容易的方法,使用-name-o,就像@janos回答的那样。我采用了Rube Goldberg regex方法 :) - David C. Rankin
1
@MikeHolt * 可能会被 shell 扩展,这不是很安全的。但是我从你那里得到了 -false 的提示,并且大大改善了我的答案,谢谢! - janos
1
@janos 嗯。看来你说得对。如果arr中的任何类型存在于顶级目录中,它将失败。所以,是的,你要么像你的答案一样构造一个参数数组,要么先使用set -o noglob。我只是喜欢单行代码 :-) - Mike Holt

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接