How to run the file command recursively

0

I'm trying to get information about the types of all the files in a given directory tree. Running file in the current directory works well enough, but it doesn't traverse into sub-directories, and there doesn't seem to an option to make it do so, which seems odd for a UNIX tool.

How exactly do I execute the file command recursively, so that it lists the file types of all the files in a given directory and its subdirectories?

Hashim

Posted 2019-10-09T21:56:39.583

Reputation: 6 967

Answers

2

The other answer provides not the best way:

find . -type f | file -f -

There are at least two problems:

  1. -f option is not required by POSIX, some implementations of file may not support it.
  2. find prints each path with a trailing newline character, so it's usually one path (file) per line. Then file -f - expects one path per line. The problem is with paths that contain newlines; they are still valid in Unix (yet uncommon). In the above approach such path will get to file in two or more lines and the tool will treat each line as a separate path to examine.

A robust and portable way:

find . -type f -exec file -- {} +

Notes:

  • -exec file {} \; would also work, but then a separate file would be invoked for every file found. With + file can get multiple operands (find is still able to call file multiple times if there are too many files to build a single command). Expect + to perform better. On the other hand file that processes multiple arguments may columnize its output, so it looks "better". Therefore the two versions (with + and with ;) may differ in formatting their outputs.
  • I used a double dash in case there's a file with name beginning with - that could be interpreted as an option. If the starting path is . (like in this case) many implementations of find will print paths starting with ., so -- is not necessary; but apparently not all implementations do this.

Kamil Maciorowski

Posted 2019-10-09T21:56:39.583

Reputation: 38 429

1

The words "all the files in a given directory and its subdirectories" should lean you toward the find command:

find . -type f | file -f -

Will recursively read all files from the current directory and sub directories and have file identify their type. You might want to add -z for types that include compression.

davolfman

Posted 2019-10-09T21:56:39.583

Reputation: 89

I suspected that, I was kinda just hoping there was an option to file that I was glossing over. It seems odd to create a tool advanced enough that it can uncompress archives to search but yet not provide a single option for recursive operation, and it's not what I've come to expect of UNIX-like tools. – Hashim – 2019-10-09T22:09:38.607

Also, is piping to file superior to using -exec? – Hashim – 2019-10-09T22:27:53.127

Yes, very. This version calls file once, exec calls it for every line, or every N lines. The forks and execs add up massively on a large operation. – davolfman – 2019-10-10T16:22:56.220

Also, the old Unix philosophy is "A set of small sharp tools". Combining tools to perform a job is part of that, so tools are built to be combined. For example putting human-output on stderr so the useful output piped form stdout is easier to work with by the next tool in line. More recent GNU and Linux stuff may not follow that exactly. – davolfman – 2019-10-10T16:26:20.933