如何递归地从一个目录中找到所有文件扩展名?

96

我该使用什么命令或命令集合来返回一个目录中(包括子目录)的所有文件扩展名?

目前,我正在使用不同的 lsgrep 组合,但我找不到可扩展的解决方案。

9个回答

142
这样怎么样:
find . -type f -name '*.*' | sed 's|.*\.||' | sort -u

但是这不会进入子目录。 - 25b3nk
1
@BhaskarChakradhar 是的,它确实可以。你为什么认为它不行呢? - Michael
谢谢,这非常有用。我正在Chromium源代码目录上使用它,并获得了数千个文件扩展名,其中许多实际上是没有文件扩展名的文件。有没有办法忽略所有没有文件扩展名的文件? - jerry
1
这也会获取所有的“点文件”,例如.ctags,这通常不是你想要的。 - DevSolar
我可以建议将“-name '.'”更改为“-name '[^.].'”,因为前者还会捕获许多“不可见”的文件,例如xemacs生成的临时编辑文件。 - Simon F
显示剩余2条评论

10

列出当前目录和所有子目录中的所有扩展名及其数量

ls -1R | sed 's/[^\.]*//' | sed 's/.*\.//' | sort | uniq -c

8
find . -type f | sed 's|.*\.||' | sort -u

同样适用于Mac操作系统。


这个解决方案不能保证所有列出的文件都有扩展名,因此没有扩展名的文件不会被sed修复,并被视为扩展名。 - Matthew

3

这是另一种方法,类似于其他方法,但只使用两个程序(find和awk)

find ./ -type f -name "*\.*" -printf "%f\n" | awk -F . '!seen[$NF]++ {print $NF}'

-type f 限制只查找文件,不包括目录。

-name "*\.*" 确保文件名中有一个 .

-printf "%f\n" 只打印文件名,不包括路径。

-F . 让awk将句点作为字段分隔符。

$NF 是最后一个字段,由句点分隔。

!seen[$NF]++ 在第一次遇到扩展名时计算为true,在每次遇到扩展名时都计算为false。

print $NF 打印扩展名。


1

如果您正在使用Bash 4+

shopt -s globstar
for file in **/*.*
do
  echo "${file##*.}
done

Ruby(1.9+)

ruby -e 'Dir["**/*.*"].each{|x|puts x.split(".")[-1]}' | sort -u

对于我使用 MSYS2,模式 "${file##*.}" 只会打印带有两个点的扩展名的最后部分(例如当扩展名为 .tar.gz 时,它只会打印 .gz)。模式 "${file#*.} 打印扩展名的每个部分。 - Alex Hall

0

使用find的另一种解决方案(甚至可以正确地排序带有嵌入式换行符的文件扩展名):

# [^.]: exclude dotfiles
find . -type f -name "[^.]*.*" -exec bash -c '
  printf "%s\000" "${@##*.}"
' argv0 '{}' + |
sort -uz | 
tr '\0' '\n'

0

我只是在谷歌搜索好答案时很快地尝试了一下。我更倾向于正则表达式而不是Bash,但这也适用于子目录。我不认为它包括没有扩展名的文件:

ls -R | egrep '(\.\w+)$' -o | sort | uniq -c | sort -r


1
不要解析ls的输出,尤其是当它没有用处时。 - gniourf_gniourf

0

又来了一个:

find * | awk -F . {'print $2'} | sort -u

1
echo 'gniourf.tar.gz' | awk -F . {'print $2'} 返回 tar,而 echo 'one.two.three.pdf' | awk -F . {'print $2'} 返回 two。您确定您的方法是正确的吗? - gniourf_gniourf
我认为上面的解决方案很简单,这里我提供另一种方法:find . -type f -name "." | awk -F. '!a[$NF]++{print $NF}'。我不认为只有一个简单的命令可以获取每种类型的文件。正如你之前所说,存在解析每行时遇到的一些问题,因此在这种情况下,最好使用一些python、perl或类似语言编写的脚本,这样就不会遇到这个问题。不管怎样,我提供了一个简单的解决方案,如果你知道文件的扩展名,可以使用grep过滤,像这样:| grep 'txt|png|pdf'。谢谢。 - ackuser

0
ls -1 | sed 's/.*\.//' | sort -u

更新: 你是对的Matthew。根据你的评论,这是一个更新版本: ls -R1 | egrep -C 0 "[^\.]+\.[^\./:]+$" | sed 's/.*\.//' | sort -u

1
这有两个问题。首先,它只适用于扁平目录,但会忽略子目录。其次,它在输出中包括所有没有扩展名的文件。 - Matthew
不要解析ls的输出,尤其是当它没有用处时。 - gniourf_gniourf
如果你有时间先安装它的话,真的应该使用ripgrep而不是egrep:https://github.com/BurntSushi/ripgrep。更新后的命令是:`ls -R1 | rg -C 0 "[^.]+.[^./:]+$" | sed 's/.*.//' | sort -u`。对于大型文件夹,我至少获得了10倍的提升。 - james-see

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