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)
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
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: 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
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
# Get just the encoding with --mime-encoding
file --mime-encoding ascii.txt utf8.txt iso8859.txt
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
#!/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
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
\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.
^M problem). Before running dos2unix, use file to confirm the file actually has DOS line endings.
# 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
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
# Get JUST the MIME type (no charset)
file --mime-type document.pdf photo.jpg webpage.html
-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.
#!/bin/bash
# Set Content-Type header based on file
FILENAME="$1"
MIME=$(file --mime-type -b "$FILENAME")
echo "Content-Type: $MIME"
cat "$FILENAME"
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
# With -z option (looks inside)
echo ""
echo "=== With -z (looks inside compression) ==="
file -z test.txt.gz test.txt.bz2 test.txt.xz
-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".
Brief Mode with -b for Clean Output
Remove the filename prefix for cleaner output in scripts.
# Normal output includes filename
file /etc/passwd
# Brief mode - just the file type
file -b /etc/passwd
# 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
-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.
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
# With -L: follows link and describes target
echo ""
echo "=== With -L (follows link to target) ==="
file -L linkfile.txt
-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
Batch Processing Multiple Files
Efficiently identify file types for many files at once.
# Check all files in a directory
file /etc/*
# 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
# 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"
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
- 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
- Web application file upload validation
- Email attachment processing
- Document management systems
- Malware scanning pipelines
- Content moderation systems
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
# 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
- 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.
# 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"
- 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
- 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)
- Filesystem tests: Check if it's a directory, device, socket, etc.
- Magic tests: Look for known byte patterns (magic numbers)
- Language tests: Analyze text for programming language syntax
- Character set tests: Determine text encoding (ASCII, UTF-8, etc.)
- Compression tests: Detect various compression formats
- 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 |