递归计算 tar 文件中文件夹中的文件数

递归计算 tar 文件中文件夹中的文件数

我进一步扩展了上一个问题来计算 tar 文件中的文件数量(关联)关于一个新问题如何计算 tar 文件中子文件夹下的文件数。我最后想要的是:

  1. 列出其中包含文件的文件夹
  2. 计算文件数量之内那个文件夹

我的例子tar 文件列表 tar -tvf myfile.tar看起来像下面(真正的tar文件有更多的文件和目录)。总共有2个文件夹,其中文件夹_文件_1内有 3 个文件 和文件夹_文件_2里面有4个文件。

drwxrwxrwx someuser/users      0 2017-08-07 11:43 ./root_folder/subfolder/folder_files_1/
-rwxr-xr-x someuser/users 538962 2017-08-07 11:43 ./root_folder/subfolder/folder_files_1/i716266.MRDC.270
-rwxr-xr-x someuser/users 538962 2017-08-07 11:43 ./root_folder/subfolder/folder_files_1/i716267.MRDC.266
-rwxr-xr-x someuser/users 538944 2017-08-07 11:43 ./root_folder/subfolder/folder_files_1/i716268.MRDC.287
drwxrwxrwx someuser/users      0 2017-08-07 11:50 ./root_folder/subfolder/folder_files_2/
-rwxr-xr-x someuser/users 538696 2017-08-07 11:50 ./root_folder/subfolder/folder_files_2/i717157.MRDC.8
-rwxr-xr-x someuser/users 538694 2017-08-07 11:50 ./root_folder/subfolder/folder_files_2/i717158.MRDC.4
-rwxr-xr-x someuser/users 538692 2017-08-07 11:50 ./root_folder/subfolder/folder_files_2/i717159.MRDC.34
-rwxr-xr-x someuser/users 538696 2017-08-07 11:50 ./root_folder/subfolder/folder_files_2/i717160.MRDC.5

我搜索过的最接近的解决方案指出我使用awk之后tar(请参阅参考资料这里这里)。

tar tvf myfile.tar | awk '/^d/ {print $0; /$6/; getline; file_no++} END {print file_no}'

/$6/就是要匹配对应的文件夹./root_folder/subfolder/folder_files_1/。但仍然无法准确统计该文件下的文件数量匹配目录, IE。文件夹文件_1、文件夹文件_2

关于如何修复我的代码有什么建议吗?

答案1

另外一个选择:

tar tf archive.tar |
    awk '
        { if (gsub("[^/]+$", "")) { h[$0]++} }
        END { for (f in h) { printf "%d\t%s\n", h[f], f } }
    '

第一个awk语句剥离文件名,并对结果目录路径的实例进行计数。第二个在输入被完全消耗时运行(即在标准输入)并打印路径列表及其各自的计数。

如果您愿意,可以将整个事情整合到一行中(只需将整个事情连接起来即可)。为了便于阅读,我将其拆分在这里。

针对 tarball 运行的结果:

4       ./root_folder/subfolder/folder_files_2/
3       ./root_folder/subfolder/folder_files_1/

答案2

tar -tvf file.tar | grep '^-' | wc -l

tar这将计算输出中以-(即文件)开头的行数。如果您的存档中有特殊类型的文件,请更改/^-为计算“除目录之外的任何内容”。/^[^d]/

另一种方法是awk

tar -tvf file.tar | awk '/^-/ { n++ } END { print n }'

这两个命令都会输出7存档中的文件总数。


如果您想为每个子文件夹单独计数:

tar -tvf file.tar | awk '/^d/ { d = $NF; next } { n[d]++ } END { for (d in n) print n[d], d }'

这会生成

4 ./root_folder/subfolder/folder_files_2/
3 ./root_folder/subfolder/folder_files_1/

您提供的数据。

最后一个示例中的代码awk从以 开头的任何行中挑选出目录名称d,并将其用作关联数组中的键。对于每个找到的文件,数组条目都会递增。最后,打印所有条目及其计数。

答案3

如果你有 GNU tar,它有一个--to-command选项:

--to-command=COMMAND
  Pipe extracted files to COMMAND.  The argument is the pathname
  of an external program, optionally with command line
  arguments.  The program will be invoked and the contents of
  the file being extracted supplied to it on its standard
  output.  Additional data will be supplied via the following
  environment variables:

  TAR_FILETYPE
         Type of the file. It is a single letter with the
         following meaning:

                 f           Regular file
                 d           Directory
                 l           Symbolic link
                 h           Hard link
                 b           Block device
                 c           Character device

         Currently only regular files are supported.
  ...
  TAR_FILENAME
         The name of the file.

这些变量可用于安全地处理带有空格等的文件名。

例如,使用 shell 字符串替换从给定路径中删除文件名,然后使用 sed 仅打印非目录的路径,然后您可以排序并应用uniq -c以获取计数:

tar xf foo.tar --to-command 'echo "$TAR_FILETYPE" "${TAR_FILENAME%/*}"' |
  sed -n '/^[^d]/s/^. //p' | 
  sort |
  uniq -c

如果您有 GNU sed、sort 和 uniq,您可以使用它们的-z选项printf "%s %s\0"echo安全地处理所有文件名。

例子:

% tar xf dev/pacaur/byobu/byobu_5.124.orig.tar.gz --to-command 'printf "%s %s\0" "$TAR_FILETYPE" "${TAR_FILENAME%/*}"' | sed -zn '/^[^d]/s/^. //p' | sort -z | uniq -zc | tr '\0' '\n'
     15 byobu-5.124
      2 byobu-5.124/Applications/Byobu.app/Contents
      1 byobu-5.124/Applications/Byobu.app/Contents/MacOS
      8 byobu-5.124/Applications/Byobu.app/Contents/Resources
      4 byobu-5.124/etc/byobu
      3 byobu-5.124/etc/profile.d
      1 byobu-5.124/experimental
     23 byobu-5.124/po
      1 byobu-5.124/snap
     38 byobu-5.124/usr/bin
     43 byobu-5.124/usr/lib/byobu
     18 byobu-5.124/usr/lib/byobu/include
      1 byobu-5.124/usr/share/appdata
      4 byobu-5.124/usr/share/byobu/desktop
     12 byobu-5.124/usr/share/byobu/keybindings
      4 byobu-5.124/usr/share/byobu/pixmaps
      1 byobu-5.124/usr/share/byobu/pixmaps/highcontrast
     11 byobu-5.124/usr/share/byobu/profiles
      4 byobu-5.124/usr/share/byobu/status
      3 byobu-5.124/usr/share/byobu/tests
      3 byobu-5.124/usr/share/byobu/windows
      3 byobu-5.124/usr/share/dbus-1/services
      4 byobu-5.124/usr/share/doc/byobu
     37 byobu-5.124/usr/share/man/man1
      1 byobu-5.124/usr/share/sounds/byobu

答案4

如果您不介意运行两次(先获取计数,然后获取行数),则可以使用 grep。

对于计数:

tar tvf myfile.tar | grep <path> | wc -l

对于线条,只需删除| wc -l

如果您只想运行tar一次,可以将输出保存到文件中,然后cat保存到 grep 和 wc。整个脚本看起来像这样:

tmp_file=$(mktemp)
tar tvf myfile.tar > $tmp_file
cat $tmp_file | grep <subdir> | wc -l
cat $tmp_file | grep <subdir>
rm $tmp_file

如果你想要一个单行代码,你可能可以通过进程替换和重定向来实现,但是如果你以任何节奏运行它,你可能最终会将它放入脚本/别名/函数中,所以这是一个更容易阅读和理解。

如果您想要 grep 出 tar 文件中的多个路径,您可以将它们全部放入一个文本文件中并使用grep -f <paths file>

相关内容