按扩展名对目录中的文件进行计数


15

为了进行测试,我想计算一个目录中有多少个图像文件,并用文件扩展名(jpg =“ yes”来分隔每种图像文件类型。这是因为稍后它将对执行动作的另一个脚本很有用在每个文件扩展名上)。我可以仅对JPEG文件使用以下内容吗?

jpg=""
count=`ls -1 *.jpg 2>/dev/null | wc -l`
if [ $count != 0 ]
then
echo jpg files found: $count ; jpg="yes"
fi

考虑到文件扩展名jpg,png,bmp,raw和其他,我应该使用while循环来做到这一点吗?

Answers:


14

我建议采用另一种方法,避免可能出现的单词拆分问题 ls

#!/bin/bash

shopt -s nullglob

for ext in jpg png gif; do 
  files=( *."$ext" )
  printf 'number of %s files: %d\n' "$ext" "${#files[@]}"

  # now we can loop over all the files having the current extension
  for f in "${files[@]}"; do
    # anything else you like with these files
    :
  done 

done

您可以files使用要在每个特定扩展名的文件上执行的任何其他命令来遍历数组。


更便于携带-或对于没有显式提供数组的shell-您可以重新使用shell的位置参数数组,即

set -- *."$ext"

然后替换${#files[@]}${files[@]}使用$#,并"$@"


23

我的方法是:

  1. 列出目录中的所有文件
  2. 提取其扩展名
  3. 排序结果
  4. 计算每个扩展的出现

有点像这样(最后一次awk调用纯粹是用于格式化):

ls -q -U | awk -F . '{print $NF}' | sort | uniq -c | awk '{print $2,$1}'

ls此处假定GNU 为-U跳过优化的选项。如果不支持,可以安全地删除它而不会影响功能)。


嗯...稍后我应该过滤找到的每个扩展,以便为此执行操作吗?
watchmansky

这最终取决于您要做什么。您能提供更多信息吗?
groxxda 2014年

我的目标是:处理每个扩展文件(仅图像文件)的脚本,以更改输入用户数据的大小。因此,我从有多少个jpg文件,下一个png等开始
watchmansky 2014年

那么,钢手解决方案可能更合适。
groxxda 2014年

2
我同时拥有JPGjpg文件,并希望递归使用它,所以我的解决方案是编写find . -type f | awk -F . '{print tolower($NF)}' | sort | uniq -c | awk '{print $2,":",$1}'
Kristian

11

这将递归遍历文件并计算匹配的扩展名:

$ find . -type f | sed -e 's/.*\.//' | sort | uniq -c | sort -n | grep -Ei '(tiff|bmp|jpeg|jpg|png|gif)$'
   6 tiff
   7 bmp
  26 jpeg
  38 gif
  51 jpg
  54 png

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

3
不要忘记使用的起始目录find。此外,如果您对解决方案进行简要说明(以防他们想为稍有不同的情况修改此解决方案),它也可以帮助将来的读者阅读这些答案。
杰夫·谢勒

该解决方案处理包含空格的路径名的效果如何?换行符?
dhag 2015年

1
find默认为当前目录,这就是我使用它的方式。我认为上帝不希望文件名中包含空格,但这在这种情况下很好用。如果您有换行符,那么您应该得到的一切。我考虑过一个解释,但认为这样做会使答案太长,我认为简单才是最重要的。在1%的时间内有99%的案例。这可能与版本7兼容。
Neik 2015年


3

任何涉及ls特殊字符(空格和其他符号)的事情都有可能产生意想不到的结果。任何bashism(例如数组)都是不可移植的。任何涉及的事情while read通常都很缓慢。

另一方面,find它非常灵活(有很多要过滤的选项),它具有[至少]两种语法,这些语法对于特殊字符是安全的...并且可以在大型目录上很好地扩展。

对于此示例,我曾经-iname同时匹配大写和小写扩展名。我还限制了-maxdepth 1尊重您的问题的“当前目录”。而不是计算文件名可以包含CR / LF的行数,而是-print0在每个文件名的末尾打印一个NULL字节...因此| tr -d -c "\000" | wc -l可以精确计数文件(NULL字节!)。

extensions="jpg png gif"
for ext in $extensions; do
  c=$(find . -maxdepth 1 -iname "*.$ext" -print0 | tr -d -c "\000" | wc -c)
  if [ $c -gt 0 ]; then
    echo "Found $c  *.$ext files"

    find . -maxdepth 1 -iname "*.$ext" -print0 | xargs -0 -r -n1 DOSOMETHINGHERE
    # or #  find . -maxdepth 1 -iname "*.$ext" -exec "ls" "-l" "{}" ";"
  fi
done

PS -print0 | tr -d -c "\000" | wc -c可以用-printf "\000" | wc -c甚至替换-printf '\n' | wc -l


0

可以将ls用于此简单的IMO

ls -l /opt/ssl/certs/*.pem | wc -l

要么

count=$(ls -l /some/folder/*.jpg | wc -l)

要么

ls *.{mp3,exe,mp4} 2>/dev/null | wc -l

-2

如果您确定要扩展,可以find

find *.jpeg | wc -l

直到有人创建,touch $'foo\nbar.jpeg并且它被计算两次而不是一次。或更糟糕的是,有人mkdir directory.jpeg; touch directory.jpeg/{1..100}.txt
这么做
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.