🔍 The file Command

Determine File Type and Characteristics

file [OPTION]... FILE...

Overview

The file command is a powerful utility that identifies the type of a file by examining its contents, not just its filename or extension. It performs sophisticated tests to determine file formats, character encodings, compression types, executable formats, and much more. This makes it invaluable for system administration, security analysis, and troubleshooting.

How file Works:

  • Examines the actual file contents (magic numbers, headers, structure)
  • Does NOT rely on file extensions
  • Performs multiple tests in a specific order
  • Consults magic number database (/usr/share/misc/magic)
  • Can identify hundreds of file types
  • Works on files with wrong or missing extensions

Key Capabilities:

  • Identify binary vs text files
  • Determine character encoding (UTF-8, ASCII, ISO-8859, etc.)
  • Recognize executable formats (ELF, PE, Mach-O)
  • Detect compression types (gzip, bzip2, xz, zip)
  • Identify archive formats (tar, cpio, ar)
  • Recognize image formats (JPEG, PNG, GIF, etc.)
  • Detect document formats (PDF, MS Office, etc.)
  • Identify scripts and their interpreters
  • Determine line ending types (Unix LF vs DOS CRLF)
Magic Numbers:

Many file formats begin with specific byte sequences called "magic numbers" that identify the file type. For example, JPEG files start with FF D8 FF, PNG files start with 89 50 4E 47, and gzip files start with 1F 8B. The file command consults a database of these magic numbers (typically stored in /usr/share/misc/magic and ~/.magic) to make its determinations.

Common Options

Option Description
-b Brief mode - don't prepend filenames to output
-i Output MIME type strings instead of human-readable descriptions
-z Try to look inside compressed files
-L Follow symbolic links
-s Read block/character special files (normally not done for safety)
-f FILE Read list of filenames to check from FILE
--mime-type Output MIME type only
--mime-encoding Output character encoding only
-k Keep going - don't stop at first match
-N Don't pad output to align

Detailed Examples

Example 1

Basic File Type Identification

The most common use - identifying what type of files you have.

# Check various common file types file /etc/passwd file /bin/bash file /usr/share/doc/README file /boot/vmlinuz-* file ~/Documents/report.pdf file ~/Pictures/photo.jpg
/etc/passwd: ASCII text /bin/bash: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=a6cb40078351e05121d46daa768e271846d5cc54, for GNU/Linux 3.2.0, stripped /usr/share/doc/README: UTF-8 Unicode text /boot/vmlinuz-5.14.0: Linux kernel x86 boot executable bzImage, version 5.14.0-362.8.1.el9_3.x86_64, RO-rootFS, swap_dev 0XA, Normal VGA /home/craig/Documents/report.pdf: PDF document, version 1.4, 24 pages /home/craig/Pictures/photo.jpg: JPEG image data, JFIF standard 1.01, resolution (DPI), density 72x72, segment length 16, baseline, precision 8, 1920x1080, components 3
Explanation: The file command examines each file and reports detailed information:
  • /etc/passwd: Plain ASCII text file
  • /bin/bash: 64-bit Linux executable (ELF format) with detailed attributes
  • README: UTF-8 encoded text (supports international characters)
  • vmlinuz: Compressed Linux kernel image
  • PDF: Identifies format, version, and page count
  • JPEG: Image format with dimensions and technical details
Pro Tip: The file command ignores file extensions completely. You could rename photo.jpg to photo.txt and it would still correctly identify it as a JPEG image!
Example 2

Detecting Character Encodings

Identify the character encoding of text files - critical for internationalization.

# Create files with different encodings echo "Hello World" > ascii.txt echo "Привет мир" > utf8.txt echo "Café résumé" > utf8_special.txt iconv -f UTF-8 -t ISO-8859-1 utf8_special.txt > iso8859.txt # Check encodings file ascii.txt utf8.txt utf8_special.txt iso8859.txt
ascii.txt: ASCII text utf8.txt: UTF-8 Unicode text utf8_special.txt: UTF-8 Unicode text iso8859.txt: ISO-8859 text
# Get just the encoding with --mime-encoding file --mime-encoding ascii.txt utf8.txt iso8859.txt
ascii.txt: us-ascii utf8.txt: utf-8 iso8859.txt: iso-8859-1
Explanation: The file command can distinguish between different character encodings by analyzing the byte patterns in the file. ASCII files use only bytes 0-127, UTF-8 uses specific multi-byte sequences, and ISO-8859 uses bytes 128-255 in specific patterns. This is essential when dealing with international text or debugging encoding issues.
Real-World Use: When receiving files from different countries or systems, checking encoding prevents display issues. Also useful before importing data into databases that expect specific encodings.
Example 3

Identifying Scripts and Interpreters

Determine what interpreter a script requires.

# Create various script types cat > script1.sh <<'EOF' #!/bin/bash echo "Bash script" EOF cat > script2.py <<'EOF' #!/usr/bin/env python3 print("Python script") EOF cat > script3.pl <<'EOF' #!/usr/bin/perl print "Perl script\n"; EOF cat > script4.rb <<'EOF' #!/usr/bin/ruby puts "Ruby script" EOF # Check all scripts file script1.sh script2.py script3.pl script4.rb
script1.sh: Bourne-Again shell script, ASCII text executable script2.py: Python script, ASCII text executable script3.pl: Perl script text executable script4.rb: Ruby script, ASCII text executable
Explanation: The file command reads the shebang line (#!/path/to/interpreter) at the beginning of the script to determine what interpreter it needs. It also identifies the file as executable if it has execute permissions. This works regardless of the file extension.
# What if the script has no shebang? cat > no_shebang.sh <<'EOF' echo "No shebang here" ls -la EOF file no_shebang.sh
no_shebang.sh: ASCII text
No Shebang: Without a shebang, file can only identify it as plain text. It can't determine that it's meant to be a shell script.
Example 4

Detecting Line Endings (Unix vs DOS/Windows)

Identify whether files have Unix (LF) or DOS/Windows (CRLF) line endings.

# Create Unix-style file (LF only) printf "Line 1\nLine 2\nLine 3\n" > unix_file.txt # Create DOS-style file (CRLF) printf "Line 1\r\nLine 2\r\nLine 3\r\n" > dos_file.txt # Check line endings file unix_file.txt dos_file.txt
unix_file.txt: ASCII text dos_file.txt: ASCII text, with CRLF line terminators
Explanation: Unix/Linux files use just LF (line feed, \n) for line endings, while DOS/Windows files use CRLF (carriage return + line feed, \r\n). The file command detects this difference by examining the byte patterns. Files with CRLF are explicitly identified as such.
Real-World Use: This is crucial when debugging scripts that fail due to DOS line endings (the infamous ^M problem). Before running dos2unix, use file to confirm the file actually has DOS line endings.
Quick Check Before Converting:
# Check if file needs dos2unix if file "$filename" | grep -q "CRLF"; then echo "Converting $filename to Unix format..." dos2unix "$filename" else echo "$filename already has Unix line endings" fi
Example 5

MIME Type Output for Web Applications

Get standardized MIME type strings suitable for HTTP headers and web applications.

# Get MIME types for various files file -i document.pdf file -i photo.jpg file -i webpage.html file -i data.json file -i archive.tar.gz file -i video.mp4
document.pdf: application/pdf; charset=binary photo.jpg: image/jpeg; charset=binary webpage.html: text/html; charset=utf-8 data.json: application/json; charset=us-ascii archive.tar.gz: application/gzip; charset=binary video.mp4: video/mp4; charset=binary
# Get JUST the MIME type (no charset) file --mime-type document.pdf photo.jpg webpage.html
document.pdf: application/pdf photo.jpg: image/jpeg webpage.html: text/html
Explanation: The -i option outputs MIME (Multipurpose Internet Mail Extensions) types in standard format (type/subtype). The --mime-type option outputs just the type without character encoding. These are the same type strings used in HTTP Content-Type headers and are standardized across platforms.
Real-World Use: Web servers and applications use this to set correct Content-Type headers:
#!/bin/bash # Set Content-Type header based on file FILENAME="$1" MIME=$(file --mime-type -b "$FILENAME") echo "Content-Type: $MIME" cat "$FILENAME"
Example 6

Looking Inside Compressed Files with -z

Examine the contents of compressed archives without decompressing them.

# Create various compressed files echo "This is a text file" > test.txt gzip -c test.txt > test.txt.gz bzip2 -c test.txt > test.txt.bz2 xz -c test.txt > test.txt.xz # Regular file output (just sees compression) echo "=== Without -z (compression only) ===" file test.txt.gz test.txt.bz2 test.txt.xz
=== Without -z (compression only) === test.txt.gz: gzip compressed data, was "test.txt", last modified: Tue Jan 15 14:23:45 2025, from Unix, original size 21 test.txt.bz2: bzip2 compressed data, block size = 900k test.txt.xz: XZ compressed data, checksum CRC64
# With -z option (looks inside) echo "" echo "=== With -z (looks inside compression) ===" file -z test.txt.gz test.txt.bz2 test.txt.xz
=== With -z (looks inside compression) === test.txt.gz: ASCII text (gzip compressed data, was "test.txt", last modified: Tue Jan 15 14:23:45 2025, from Unix, original size 21) test.txt.bz2: ASCII text (bzip2 compressed data, block size = 900k) test.txt.xz: ASCII text (XZ compressed data, checksum CRC64)
Explanation: The -z option tells file to decompress the file temporarily and identify the contents inside. This is extremely useful for identifying what's in archives without actually extracting them. Notice how with -z it identifies the compressed file contains "ASCII text".
Pro Tip: This works with nested compression too! A file compressed with gzip that contains a tar archive will be identified as a tar archive.
Example 7

Brief Mode with -b for Clean Output

Remove the filename prefix for cleaner output in scripts.

# Normal output includes filename file /etc/passwd
/etc/passwd: ASCII text
# Brief mode - just the file type file -b /etc/passwd
ASCII text
# Useful in scripts for cleaner variable assignment FILETYPE=$(file -b /etc/passwd) echo "File type is: $FILETYPE" # Check if file is text or binary if file -b "$filename" | grep -q "text"; then echo "Text file - safe to display" cat "$filename" else echo "Binary file - use hexdump or specialized viewer" fi
File type is: ASCII text Text file - safe to display [contents of file...]
Explanation: The -b (brief) option omits the filename from the output, leaving just the file type description. This is perfect for scripts where you want to capture just the type information without parsing out the filename portion.
Example 8

Following Symbolic Links with -L

Examine the target of symbolic links instead of the link itself.

# Create a file and a symbolic link to it echo "This is the actual file content" > realfile.txt ln -s realfile.txt linkfile.txt # Without -L: describes the link itself echo "=== Without -L (describes link) ===" file linkfile.txt
=== Without -L (describes link) === linkfile.txt: symbolic link to realfile.txt
# With -L: follows link and describes target echo "" echo "=== With -L (follows link to target) ===" file -L linkfile.txt
=== With -L (follows link to target) === linkfile.txt: ASCII text
Explanation: By default, file tells you about the symbolic link itself. With -L, it follows the link and reports on the target file. This is useful when you want to know what type of file a link points to, not just that it's a link.
# Practical example: find what /usr/bin/python points to file /usr/bin/python file -L /usr/bin/python
/usr/bin/python: symbolic link to python3.9 /usr/bin/python: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, stripped
Real-World Use: Useful when troubleshooting broken links or verifying that system commands point to the correct executables.
Example 9

Batch Processing Multiple Files

Efficiently identify file types for many files at once.

# Check all files in a directory file /etc/*
/etc/bashrc: ASCII text /etc/crontab: ASCII text /etc/fstab: ASCII text /etc/group: ASCII text /etc/hosts: ASCII text /etc/passwd: ASCII text /etc/resolv.conf: ASCII text [... many more files ...]
# Read filenames from a file using -f find /var/log -type f > filelist.txt file -f filelist.txt
# Find all non-text files in a directory find /home/craig/Documents -type f -exec file {} \; | \ grep -v "text" | \ cut -d: -f1
/home/craig/Documents/report.pdf /home/craig/Documents/spreadsheet.xlsx /home/craig/Documents/presentation.pptx /home/craig/Documents/photo.jpg
# Categorize files by type #!/bin/bash # categorize-files.sh echo "=== File Type Summary ===" echo "" file * | awk -F: '{print $2}' | \ sed 's/^[[:space:]]*//' | \ sort | uniq -c | sort -rn echo "" echo "=== Images ===" file * | grep -i "image" echo "" echo "=== Documents ===" file * | grep -E "PDF|Word|Excel|PowerPoint" echo "" echo "=== Archives ===" file * | grep -E "gzip|bzip2|xz|tar|zip"
=== File Type Summary === 15 ASCII text 8 JPEG image data 5 PDF document 3 gzip compressed data 2 Python script 1 Bourne-Again shell script === Images === photo1.jpg: JPEG image data, JFIF standard 1.01 photo2.jpg: JPEG image data, JFIF standard 1.01 [...] === Documents === report.pdf: PDF document, version 1.7 presentation.pdf: PDF document, version 1.4 === Archives === backup.tar.gz: gzip compressed data, from Unix data.tar.bz2: bzip2 compressed data logs.tar.xz: XZ compressed data
Explanation: The file command handles multiple files efficiently and can process wildcards, lists from files, or output from find. The categorization script demonstrates how to use file output for classification and reporting.
Example 10

Complete File Analysis and Validation Script

A production-ready script using file for comprehensive file validation and reporting.

#!/bin/bash # validate-upload.sh - Validate uploaded files before processing # Uses file command to verify file types regardless of extension set -euo pipefail readonly ALLOWED_IMAGES=("image/jpeg" "image/png" "image/gif") readonly ALLOWED_DOCS=("application/pdf" "text/plain") readonly MAX_SIZE_MB=10 # Color codes readonly RED='\033[0;31m' readonly GREEN='\033[0;32m' readonly YELLOW='\033[1;33m' readonly NC='\033[0m' log_error() { echo -e "${RED}[ERROR]${NC} $*" >&2 } log_success() { echo -e "${GREEN}[OK]${NC} $*" } log_warn() { echo -e "${YELLOW}[WARN]${NC} $*" } # Check if file is allowed image type is_allowed_image() { local file="$1" local mime=$(file --mime-type -b "$file") for allowed in "${ALLOWED_IMAGES[@]}"; do if [ "$mime" = "$allowed" ]; then return 0 fi done return 1 } # Check if file is allowed document type is_allowed_doc() { local file="$1" local mime=$(file --mime-type -b "$file") for allowed in "${ALLOWED_DOCS[@]}"; do if [ "$mime" = "$allowed" ]; then return 0 fi done return 1 } # Check file size check_size() { local file="$1" local size_bytes=$(stat -f%z "$file" 2>/dev/null || stat -c%s "$file") local size_mb=$((size_bytes / 1048576)) if [ $size_mb -gt $MAX_SIZE_MB ]; then log_error "File too large: ${size_mb}MB (max: ${MAX_SIZE_MB}MB)" return 1 fi return 0 } # Detect potential security issues check_security() { local file="$1" local filetype=$(file -b "$file") # Check for executable files if echo "$filetype" | grep -qi "executable"; then log_error "Executable files not allowed" return 1 fi # Check for scripts if echo "$filetype" | grep -qi "script"; then log_error "Script files not allowed" return 1 fi # Check for suspicious content in images if file --mime-type -b "$file" | grep -q "^image/"; then if grep -q "<script" "$file" 2>/dev/null; then log_error "Suspicious content detected in image" return 1 fi fi return 0 } # Main validation function validate_file() { local file="$1" local category="$2" # "image" or "document" echo "Validating: $file" echo "Category: $category" # Check if file exists if [ ! -f "$file" ]; then log_error "File not found" return 1 fi # Get file details local mime=$(file --mime-type -b "$file") local encoding=$(file --mime-encoding -b "$file") local description=$(file -b "$file") echo "MIME type: $mime" echo "Encoding: $encoding" echo "Description: $description" echo "" # Check file size if ! check_size "$file"; then return 1 fi log_success "Size check passed" # Check security if ! check_security "$file"; then return 1 fi log_success "Security check passed" # Validate against allowed types case "$category" in image) if is_allowed_image "$file"; then log_success "Valid image type: $mime" else log_error "Image type not allowed: $mime" log_error "Allowed types: ${ALLOWED_IMAGES[*]}" return 1 fi ;; document) if is_allowed_doc "$file"; then log_success "Valid document type: $mime" else log_error "Document type not allowed: $mime" log_error "Allowed types: ${ALLOWED_DOCS[*]}" return 1 fi ;; *) log_error "Unknown category: $category" return 1 ;; esac # Check for DOS line endings in text files if [ "$mime" = "text/plain" ]; then if file "$file" | grep -q "CRLF"; then log_warn "File has DOS/Windows line endings (CRLF)" log_warn "Consider converting with: dos2unix $file" fi fi echo "" log_success "File validation passed: $file" return 0 } # Usage if [ $# -ne 2 ]; then echo "Usage: $0 <file> <category>" echo "Categories: image, document" exit 1 fi FILE="$1" CATEGORY="$2" echo "==========================================" echo "File Upload Validation" echo "==========================================" echo "" if validate_file "$FILE" "$CATEGORY"; then echo "" echo "==========================================" log_success "VALIDATION PASSED" echo "File is safe to process: $FILE" exit 0 else echo "" echo "==========================================" log_error "VALIDATION FAILED" echo "File rejected: $FILE" exit 1 fi
========================================== File Upload Validation ========================================== Validating: photo.jpg Category: image MIME type: image/jpeg Encoding: binary Description: JPEG image data, JFIF standard 1.01, resolution (DPI), density 72x72, segment length 16, baseline, precision 8, 1920x1080, components 3 [OK] Size check passed [OK] Security check passed [OK] Valid image type: image/jpeg [OK] File validation passed: photo.jpg ========================================== [OK] VALIDATION PASSED File is safe to process: photo.jpg
Explanation: This production-quality script demonstrates comprehensive file validation:
  • Uses file command to determine actual file type (not extension)
  • Validates against whitelist of allowed MIME types
  • Checks file size limits
  • Detects executable files and scripts (security risk)
  • Scans images for suspicious content
  • Warns about DOS line endings in text files
  • Provides detailed logging and error messages
Real-World Application:
  • Web application file upload validation
  • Email attachment processing
  • Document management systems
  • Malware scanning pipelines
  • Content moderation systems
Security Note: Never trust file extensions alone! Attackers can rename malicious files. Always use the file command to verify actual content before processing uploads.

Common File Types and Descriptions

File Type file Command Output MIME Type
Text Files ASCII text, UTF-8 Unicode text text/plain
Shell Scripts Bourne-Again shell script, ASCII text executable text/x-shellscript
Python Scripts Python script, ASCII text executable text/x-python
Linux Executables ELF 64-bit LSB executable, x86-64... application/x-executable
JPEG Images JPEG image data, JFIF standard... image/jpeg
PNG Images PNG image data, 1920 x 1080, 8-bit/color... image/png
GIF Images GIF image data, version 89a... image/gif
PDF Documents PDF document, version 1.4 application/pdf
HTML Files HTML document, ASCII text text/html
XML Files XML 1.0 document, ASCII text application/xml
JSON Files JSON data application/json
gzip Archives gzip compressed data, from Unix... application/gzip
tar Archives POSIX tar archive (GNU) application/x-tar
ZIP Archives Zip archive data, at least v2.0... application/zip
Symbolic Links symbolic link to [target] inode/symlink

Additional Information

Finding the Magic Database:
# Main magic database ls -lh /usr/share/misc/magic # Compiled version (faster) ls -lh /usr/share/misc/magic.mgc # User's personal magic database ls -lh ~/.magic
Why File Extensions Are Unreliable:
  • Users can rename files to any extension
  • Different systems use different conventions
  • Malware often uses misleading extensions
  • Downloaded files may have wrong extensions
  • Some files have no extensions at all (Unix tradition)

The file command examines actual content, making it reliable for security and validation.

Useful File Command Patterns:
# Find all script files find . -type f -exec file {} \; | grep "script" # Find files with DOS line endings find . -type f -exec file {} \; | grep "CRLF" # Count files by type file * | awk -F: '{print $2}' | sort | uniq -c # Find binary executables file * | grep "executable" # Find non-ASCII text files file * | grep -v "ASCII" | grep "text" # Get MIME types for web content find /var/www -type f -exec file --mime-type {} \; # Find compressed files file * | grep -E "gzip|bzip2|xz|compress"
Limitations:
  • Not 100% accurate - heuristics can be fooled
  • New file formats may not be recognized
  • Encrypted files appear as random data
  • Some formats are difficult to distinguish
  • Custom/proprietary formats may not be in database
Security Applications:
  • Malware detection (identifying disguised executables)
  • File upload validation (preventing malicious uploads)
  • Forensic analysis (determining file types without extensions)
  • Data recovery (identifying file types on corrupted media)
  • Email attachment scanning (detecting threats)
How file Makes Its Determination:
  1. Filesystem tests: Check if it's a directory, device, socket, etc.
  2. Magic tests: Look for known byte patterns (magic numbers)
  3. Language tests: Analyze text for programming language syntax
  4. Character set tests: Determine text encoding (ASCII, UTF-8, etc.)
  5. Compression tests: Detect various compression formats
  6. Fallback: If nothing else matches, report as "data"

Quick Reference

Task Command
Basic file type file filename
MIME type file -i filename
MIME type only file --mime-type filename
Character encoding file --mime-encoding filename
Brief output (no filename) file -b filename
Look inside compressed file -z filename.gz
Follow symbolic links file -L linkname
Multiple files file file1 file2 file3
All files in directory file *
Check if text file file -b filename | grep -q text