如何在文件夹层次结构中找到所有不同的文件扩展名?

时间:2009-12-03 19:18:49

标签: linux grep filesystems file-extension

在Linux机器上,我想遍历文件夹层次结构并获取其中所有不同文件扩展名的列表。

从shell实现这一目标的最佳方法是什么?

17 个答案:

答案 0 :(得分:298)

尝试这个(不确定它是否是最佳方式,但它有效):

find . -type f | perl -ne 'print $1 if m/\.([^.\/]+)$/' | sort -u

它的工作原理如下:

  • 查找当前文件夹中的所有文件
  • 打印文件扩展名(如果有)
  • 制作一个独特的排序列表

答案 1 :(得分:42)

无需管道sort,awk可以完成所有操作:

find . -type f | awk -F. '!a[$NF]++{print $NF}'

答案 2 :(得分:31)

递归版:

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

如果你想要总数(看到扩展的时间有多少):

find . -type f | sed -e 's/.*\.//' | sed -e 's/.*\///' | sort | uniq -c | sort -rn

非递归(单个文件夹):

for f in *.*; do printf "%s\n" "${f##*.}"; done | sort -u

我的基础是this forum post,应该归功于此。

答案 3 :(得分:21)

Powershell的:

dir -recurse | select-object extension -unique

感谢http://kevin-berridge.blogspot.com/2007/11/windows-powershell.html

答案 4 :(得分:11)

使用点查找everythin并仅显示后缀。

find . -type f -name "*.*" | awk -F. '{print $NF}' | sort -u

如果您知道所有后缀都有3个字符,那么

find . -type f -name "*.???" | awk -F. '{print $NF}' | sort -u

或使用sed显示所有带有一到四个字符的后缀。将{1,4}更改为后缀中预期的字符范围。

find . -type f | sed -n 's/.*\.\(.\{1,4\}\)$/\1/p'| sort -u

答案 5 :(得分:7)

在混音中添加我自己的变奏曲。我认为这是最简单的,当效率不是一个大问题时可能会有用。

find . -type f | grep -o -E '\.[^\.]+$' | sort -u

答案 6 :(得分:5)

我在这里尝试了很多答案,甚至是“最好”的答案。他们都没有达到我特别追求的目标。因此,除了过去12个小时的多个程序的正则表达式代码以及阅读和测试这些答案之外,这就是我想出来的,它完全像我想要的那样。

 find . -type f -name "*.*" | grep -o -E "\.[^\.]+$" | grep -o -E "[[:alpha:]]{2,16}" | awk '{print tolower($0)}' | sort -u
  • 查找可能具有扩展名的所有文件。
  • 仅限扩展
  • Greps表示2到16个字符之间的文件扩展名(如果它们不符合您的需要,只需调整数字)。这有助于避免缓存文件和系统文件(系统文件位是搜索jail)。
  • 以小写字母打印扩展程序。
  • 排序并仅引入唯一值。最初我曾试图尝试awk答案,但它会使案例敏感度不同的打印项目加倍。

如果您需要计算文件扩展名,请使用以下代码

find . -type f -name "*.*" | grep -o -E "\.[^\.]+$" | grep -o -E "[[:alpha:]]{2,16}" | awk '{print tolower($0)}' | sort | uniq -c | sort -rn

虽然这些方法需要一些时间才能完成,而且可能不是解决问题的最佳方法,但它们可以正常工作。

更新: Per @ alpha_989长文件扩展名会导致问题。这是由于原始的正则表达式“[[:alpha:]] {3,6}”。我更新了答案,包括正则表达式“[[:alpha:]] {2,16}”。但是,使用此代码的任何人都应该知道这些数字是最终输出允许扩展的最小值和最大值。超出该范围的任何内容都将在输出中分成多行。

注意:原帖显示为“ - 文件扩展名为3到6个字符的Greps(如果它们不符合您的需要,只需调整数字)。这有助于避免缓存文件和系统文件(系统文件位是搜索牢)。“

创意:可用于通过以下方式查找特定长度的文件扩展名:

 find . -type f -name "*.*" | grep -o -E "\.[^\.]+$" | grep -o -E "[[:alpha:]]{4,}" | awk '{print tolower($0)}' | sort -u

其中4是要包含的文件扩展名长度,然后查找超出该长度的任何扩展名。

答案 7 :(得分:4)

在Python中使用生成器来处理非常大的目录,包括空白扩展,并获取每个扩展显示的次数:

import json
import collections
import itertools
import os

root = '/home/andres'
files = itertools.chain.from_iterable((
    files for _,_,files in os.walk(root)
    ))
counter = collections.Counter(
    (os.path.splitext(file_)[1] for file_ in files)
)
print json.dumps(counter, indent=2)

答案 8 :(得分:3)

我的少awk,少sed,少Perl,少Python的POSIX兼容替代方案:

find . -type f | rev | cut -d. -f1 | rev  | tr '[:upper:]' '[:lower:]' | sort | uniq --count | sort -rn

诀窍在于,它可以将行颠倒并在开始处剪切扩展名。
还将扩展名转换为小写。

示例输出:

   3689 jpg
   1036 png
    610 mp4
     90 webm
     90 mkv
     57 mov
     12 avi
     10 txt
      3 zip
      2 ogv
      1 xcf
      1 trashinfo
      1 sh
      1 m4v
      1 jpeg
      1 ini
      1 gqv
      1 gcs
      1 dv

答案 9 :(得分:2)

因为已经有另一种使用Perl的解决方案:

如果你安装了Python,你也可以(从shell):

python -c "import os;e=set();[[e.add(os.path.splitext(f)[-1]) for f in fn]for _,_,fn in os.walk('/home')];print '\n'.join(e)"

答案 10 :(得分:2)

我不认为这个提到了:

find . -type f -exec sh -c 'echo "${0##*.}"' {} \; | sort | uniq -c

答案 11 :(得分:1)

到目前为止,所有回复都没有正确处理带有换行符的文件名(ChristopheD除外,因为我输入的内容刚刚进入)。以下不是shell单线程,但有效,并且速度相当快。

import os, sys

def names(roots):
    for root in roots:
        for a, b, basenames in os.walk(root):
            for basename in basenames:
                yield basename

sufs = set(os.path.splitext(x)[1] for x in names(sys.argv[1:]))
for suf in sufs:
    if suf:
        print suf

答案 12 :(得分:1)

我认为最简单的&直截了当的方式是

for f in *.*; do echo "${f##*.}"; done | sort -u

在ChristopheD的第三条道路上进行了修改。

答案 13 :(得分:0)

另一种方式:

find . -type f -name "*.*" -printf "%f\n" | while IFS= read -r; do echo "${REPLY##*.}"; done | sort -u

您可以删除 -name "*.*",但这可确保我们只处理具有某种扩展名的文件。

-printffind 的打印,而不是 bash。 -printf "%f\n" 仅打印文件名,去除路径(并添加换行符)。

然后我们使用字符串替换使用 ${REPLY##*.} 删除最后一个点。

请注意,$REPLY 只是 read 的内置变量。我们可以使用我们自己的形式:while IFS= read -r file,这里 $file 就是变量。

答案 14 :(得分:0)

接受的答案使用REGEX,并且您无法使用REGEX创建别名命令,您必须将其放入外壳脚本中,我使用的是Amazon Linux 2,并执行了以下操作:

  1. 我使用:

    将接受的答案代码放入文件中

    sudo vim find.sh

添加此代码:

find ./ -type f | perl -ne 'print $1 if m/\.([^.\/]+)$/' | sort -u

通过输入以下内容保存文件::wq!

  1. sudo vim ~/.bash_profile

  2. alias getext=". /path/to/your/find.sh"

  3. :wq!

  4. . ~/.bash_profile

答案 15 :(得分:0)

我发现它简单快捷...

   # find . -type f -exec basename {} \; | awk -F"." '{print $NF}' > /tmp/outfile.txt
   # cat /tmp/outfile.txt | sort | uniq -c| sort -n > tmp/outfile_sorted.txt

答案 16 :(得分:0)

你也可以这样做

find . -type f -name "*.php" -exec PATHTOAPP {} +