Identify Files Reliably with file, MIME Output and Magic Rules

A download arrives with no extension, and file is the command that tells you what it actually is before you open it. You will finish with a repeatable way to identify ordinary files, produce MIME-oriented output for scripts, inspect links without accidentally following them, and test a private magic(5) rule. The examples use file 5.45 from Debian package file version 1:5.45-3build1, with libmagic1t64 at the same version.

Allow about fifteen minutes. You need a shell and a path you can read. The normal examples are unprivileged and read-only. Do not use file -s on a block or character device unless you have identified the device and accept the risk of reading it; reserve that option for deliberate inspection of raw storage.

1. Confirm the installed command

Check the executable and version before relying on an output detail:

$ command -v file
/usr/bin/file
$ file --version
file-5.45
magic file from /etc/magic:/usr/share/misc/magic

The manpage documents version 5.45. The last line is useful context: the command is loading magic data from the system locations shown there. If your version differs, read its local manpage before copying an option into automation.

Checkpoint: If command -v file prints an unexpected path, stop and inspect that installation rather than assuming it behaves like /usr/bin/file.

2. Identify one or several paths

Pass one or more paths as arguments. The filename is normally printed before the classification, separated by a colon:

$ file /etc/hosts /bin/sh
/etc/hosts: ASCII text
/bin/sh: symbolic link to dash

The exact wording depends on the local files and magic database. The useful model is that file tries filesystem tests first, then magic-pattern tests, then text and language tests. It stops at the first successful test. A filename extension is only a hint to you, not the primary basis for this result.

For a compact result without the path prefix, use brief mode:

$ file --brief /etc/hosts
ASCII text

Use --brief when a script already knows which input it is reporting. For a human-facing list, keeping the filename is usually less confusing.

3. Choose safe symlink behaviour

This installed command does not follow symbolic links by default when POSIXLY_CORRECT is unset. Ask for the link itself with --no-dereference, or explicitly follow it with --dereference:

$ file --no-dereference /bin/sh
/bin/sh: symbolic link to dash
$ file --dereference /bin/sh
/bin/sh: ELF 64-bit LSB pie executable, ...

The ELF description is abbreviated here because it varies with the host. The second command reads the target, not merely the link metadata. That distinction matters when a path may be replaced or redirected by another process. Use --no-dereference when you are auditing the link itself; use --dereference only when the target is the object you mean to classify.

Checkpoint: Compare the two commands on a link you control. If POSIXLY_CORRECT is set in a service environment, do not depend on the default. Pass the option explicitly.

4. Produce MIME output for a pipeline

Human descriptions are useful at a terminal but awkward to parse. Use --mime-type for the type alone, or --mime-encoding for the character encoding:

$ file --mime-type --brief /etc/hosts
text/plain
$ file --mime-encoding --brief /etc/hosts
us-ascii

The combined --mime or short -i form includes both pieces, for example text/plain; charset=us-ascii. Treat the value as a classification, not proof that content is safe to execute or parse. A file can be mislabeled, deliberately ambiguous or crafted to exercise a parser.

For a batch where each result must remain associated with its input, keep the filename in the output. If another program needs NUL-terminated records, add --print0. It terminates each result with a NUL character, but the normal filename separator remains in place, so verify the receiving program's expected record format before changing a production pipeline.

5. Investigate a mismatch without changing the input

When a result is surprising, ask for all matching descriptions with --keep-going:

$ file --keep-going /path/to/INPUT
/path/to/INPUT: first matching description\012- second matching description

The descriptions are separated using an escaped line-feed marker in the normal output. The strongest magic pattern is listed first. This can show why a file was classified in a particular way, but it is not a verdict that every listed format is valid. Inspect a copy or use a format-specific validator when validity matters.

If the path does not exist or cannot be read, the default behaviour reports the problem and continues with other arguments. Add -E when an unreadable or missing input must make the command fail:

$ file -E /path/to/INPUT
file: cannot open `/path/to/INPUT' (No such file or directory)
$ printf 'exit status: %s\n' "$?"
exit status: 1

The exact diagnostic varies. The useful contract is the exit status: zero means the operation succeeded, while a value greater than zero means an error. Capture it immediately if a script needs to distinguish failure from a classification such as data.

6. Test a private magic rule

magic(5) files describe tests as an offset, a type and a message. A small private rule is safer to experiment with than editing system data. Create a temporary sample and rule:

$ workdir=$(mktemp -d)
$ printf 'TOKEN\nexample\n' > "$workdir/sample.bin"
$ printf '0\tstring\tTOKEN\tToken example data\n' > "$workdir/example.magic"
$ file --magic-file "$workdir/example.magic" "$workdir/sample.bin"
/tmp/tmp.XXXXXX/sample.bin: Token example data

The temporary directory name is deliberately variable. The rule tests bytes at offset zero and emits its message when the five-byte string matches. The command reads the source rule directly. For repeated use, --compile writes a parsed magic.mgc file, and --checking-printout can show the parsed form before installation.

Do not install a rule globally just to solve a one-off classification problem. Magic entry order affects matching, and a private file passed with --magic-file keeps the experiment scoped to the command. When finished, remove only the temporary directory you created:

$ rm -rf -- "$workdir"
$ test ! -e "$workdir" && printf '%s\n' 'temporary test removed'
temporary test removed

This is the one destructive command in the guide. Check that workdir contains the value from mktemp -d before running it. There is no recovery for files placed in that directory after removal, so copy out anything you intend to keep first.

7. Keep the boundaries clear

By default, file avoids reading special files. --special-files changes that and can read block or character devices, including raw partitions. Treat it as an elevated-risk diagnostic option even when the command itself does not require sudo. The guide does not use it. Similarly, --uncompress and --uncompress-noreport inspect compressed contents. Review the input and local security posture before asking a tool to decompress untrusted data.

The Debian build reports that its --no-sandbox option has no effect because it was built without seccomp support. Do not treat that option as a security control on this installation. Check file --help and the local manpage when portability or sandboxing is part of your threat model.

Done means