2

I need to count directories inside an archive file (e.g. tar.bz) without extracting the archive. Note that the archive is too big so that it will be hard to extract then count directories using ls | wc -l.

  • Top-level directories or including every subdirectory? – Jeff Schaller Mar 26 '19 at 12:06
  • I want to count top-level directories actually? But if you can give a hint on how to recursively count or specify a certain depth, it would be perfect. – Tung Mar 26 '19 at 12:09
3

This should list all the files from the archive, then find the lines ending with / (folders) and then take the line count of it:

tar -tvf file.tar | grep -c '/$'

edit: if you want to only count the top level dirs:

tar --exclude='./*/*' -tvf file.tar | grep -c '/$'

If you want to go recursively one level deeper:

tar --exclude='./*/*/*' -tvf file.tar | grep -c '/$'

and so on...

  • This may work in some cases but does not work in general since only historic TAR implementations need to append a slash to the end of directory names. – schily Apr 2 '19 at 17:09
0

The only method that works correctly in all cases is to use star -find:

star -t -v -f file.tar -find -type d | wc -l

works in all cases, even when the directory names do not end in a slash. The dirty trick to append a slash to directory names has been introduced around 1980, when the tar format did not yet know about the file type "directory". POSIX does not require it and there are tar implementations that do not append the slash to directory names.

Note that you may need to grep for '^ 0 d' in order to make sure that you only count the beginning of real list lines in case that the pathnames contain newline characters, or by using:

star -t -f file.tar -find -type d -print0 -false

and then to count the number of nul characters in the output like by piping the output to:

LC_ALL=C tr -cd '\0' | wc -c
0

With GNU tar or bsdtar, you can use:

tar tvf file.tar | grep -c '^d'

Both GNU tar and bsdtar give the file type as the first character on the line in the long list output (tv) in a similar way as ls -l and render newlines in file names as \n, so that still works if archive member names contain newline character.

That's more reliable than looking for trailing / characters which like @schily says are not guaranteed to be there.

POSIXly, you can use:

pax -o listopt=%.1M < file.tar | grep -cx d

Though that -o listopt is not supported by all pax implementations, in particular not the http://www.mirbsd.org/pax.htm pax found on Ubuntu.

pax -v < file.tar | grep -c '^d'

would be more portable but could fail with file names that contain newline characters.

  • The first and the third proposal do not work, when a filename contains the pair ''newline d'', the second proposal only works with the pax implementation found on Solaris or AIX. If you like to have a method that works on many platforms, star -find seems to be the best solution. – schily Apr 3 '19 at 9:29
  • @schily, no, as I said both bsdtar and GNU tar render newline as \n. I've already mentioned the newline problem with pax -v and the fact that -o listopt is not widely supported. – Stéphane Chazelas Apr 3 '19 at 10:12

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.