Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

File Sharing with Linux and BSD

Moving files between macOS and Linux or BSD systems seems straightforward until you encounter the edge cases: files that vanish because of case sensitivity, mysterious extended attributes polluting your archives, or scripts that fail because of invisible line ending differences. This chapter covers these common issues and provides solutions for reliable cross-platform file sharing.

Case Sensitivity: The Silent Problem

By default, macOS uses a case-insensitive (but case-preserving) filesystem. Linux and BSD use case-sensitive filesystems. This difference causes real problems.

The Problem

# On macOS (case-insensitive)
$ touch README.md readme.md
$ ls
README.md  # Only one file exists!

# On Linux (case-sensitive)
$ touch README.md readme.md
$ ls
README.md  readme.md  # Two distinct files

When you clone a repository on macOS that contains both File.txt and file.txt (created on Linux), one will silently overwrite the other.

Detecting Case Conflicts

Check for case conflicts before they cause problems:

# Find potential case conflicts in current directory
find . -type f | sort -f | uniq -di

# More comprehensive check (shows conflicting pairs)
find . -type f -print0 | \
  xargs -0 -n1 basename | \
  sort -f | uniq -di | while read name; do
    find . -iname "$name" -type f
    echo "---"
  done

# Check a git repository for case conflicts
git ls-files | sort -f | uniq -di

Solutions

Option 1: Create a Case-Sensitive Volume

For development that must match Linux behavior:

# Create a case-sensitive APFS volume
$ diskutil apfs addVolume disk1 "Case-sensitive APFS" CaseSensitive

# Mount point will be at /Volumes/CaseSensitive
$ cd /Volumes/CaseSensitive
$ touch README.md readme.md
$ ls
README.md  readme.md  # Both files exist

Option 2: Create a Case-Sensitive Disk Image

For a portable solution:

# Create a sparse image with case-sensitive filesystem
$ hdiutil create -size 10g -fs "Case-sensitive APFS" \
    -type SPARSE -volname "DevWork" ~/DevWork.sparseimage

# Mount it
$ hdiutil attach ~/DevWork.sparseimage
/dev/disk4          	GUID_partition_scheme
/dev/disk4s1        	EFI
/dev/disk4s2        	Apple_APFS
/dev/disk5          	EFI
/dev/disk5s1        	XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX	/Volumes/DevWork

# Use it
$ cd /Volumes/DevWork

Option 3: Git Configuration

Configure Git to warn about case issues:

# Enable case-sensitivity checking
$ git config core.ignoreCase false

# This will cause Git to notice case-only renames

Option 4: Rename Files to Avoid Conflicts

The simplest solution when possible:

# On Linux, rename conflicting files
$ mv file.txt file_lower.txt
$ mv File.txt File_upper.txt

Extended Attributes and Resource Forks

macOS extensively uses extended attributes for metadata. These cause problems when sharing files with Linux/BSD.

The Problem

# On macOS, files acquire extended attributes
$ ls -l@ file.txt
-rw-r--r--@ 1 user staff 100 Jan 1 12:00 file.txt
    com.apple.quarantine	     57
    com.apple.lastuseddate#PS	     16

# When archived, these create ._ files (AppleDouble format)
$ tar czf archive.tar.gz folder/
$ tar tzf archive.tar.gz | grep "._"
folder/._file.txt
folder/._image.png

On Linux, these ._ files litter your directories:

# On Linux after extracting
$ ls -la
-rw-r--r-- 1 user user  100 Jan  1 12:00 file.txt
-rw-r--r-- 1 user user  289 Jan  1 12:00 ._file.txt  # What is this?

Understanding Extended Attributes

View extended attributes on macOS:

# List extended attributes
$ xattr file.txt
com.apple.quarantine
com.apple.lastuseddate#PS

# View attribute contents
$ xattr -p com.apple.quarantine file.txt
0083;5f4c1234;Safari;1234ABCD-5678-EFGH-IJKL-MNOPQRSTUVWX

# Common macOS extended attributes
# com.apple.quarantine     - File downloaded from internet
# com.apple.FinderInfo     - Finder metadata
# com.apple.ResourceFork   - Classic Mac resource data
# com.apple.lastuseddate#PS - Last opened date
# com.apple.metadata:*     - Spotlight metadata

Removing Extended Attributes

Before sharing files with other systems:

# Remove all extended attributes from a file
$ xattr -c file.txt

# Remove all extended attributes recursively
$ xattr -rc folder/

# Remove specific attribute
$ xattr -d com.apple.quarantine file.txt

# Remove quarantine attribute from downloaded app
$ xattr -dr com.apple.quarantine /Applications/SomeApp.app

Creating Clean Archives

For archives meant for Linux/BSD systems:

# Method 1: Use tar with --no-xattrs (if available)
$ tar --no-xattrs -czf archive.tar.gz folder/

# Method 2: Strip attributes first
$ xattr -rc folder/
$ tar czf archive.tar.gz folder/

# Method 3: Use COPYFILE_DISABLE to prevent AppleDouble files
$ COPYFILE_DISABLE=1 tar czf archive.tar.gz folder/

# Method 4: For zip files
$ zip -r -X archive.zip folder/  # -X excludes extra file attributes

# Verify archive is clean
$ tar tzf archive.tar.gz | grep "._"
# Should return nothing

Cleaning Received Archives

When you receive archives with ._ files:

# Remove AppleDouble files
$ find . -name "._*" -delete

# Alternative: use dot_clean utility
$ dot_clean folder/
# This merges ._ files back into their parent files or removes them

Line Endings: The Invisible Difference

Different operating systems use different line endings:

  • Unix/Linux/macOS: LF (\n, 0x0A)
  • Windows: CRLF (\r\n, 0x0D 0x0A)
  • Classic Mac (pre-OS X): CR (\r, 0x0D)

Detecting Line Ending Issues

# Check file line endings
$ file script.sh
script.sh: Bourne-Again shell script, ASCII text executable

$ file windows_script.sh
windows_script.sh: Bourne-Again shell script, ASCII text executable, with CRLF line terminators

# Using cat -v to see carriage returns
$ cat -v windows_script.sh | head -2
#!/bin/bash^M
echo "Hello"^M

# Using hexdump
$ hexdump -C script.sh | head -2
00000000  23 21 2f 62 69 6e 2f 62  61 73 68 0a              |#!/bin/bash.|

Converting Line Endings

# Using dos2unix (install via Homebrew)
$ brew install dos2unix

# Convert Windows to Unix
$ dos2unix file.txt

# Convert Unix to Windows
$ unix2dos file.txt

# Convert multiple files
$ dos2unix *.sh

# Without dos2unix, use sed
# Remove CR characters (Windows → Unix)
$ sed -i '' 's/\r$//' file.txt

# Using tr
$ tr -d '\r' < windows_file.txt > unix_file.txt

# Using Perl (often more reliable for binary safety)
$ perl -pi -e 's/\r\n/\n/g' file.txt

Git Configuration for Line Endings

Configure Git to handle line endings automatically:

# For cross-platform projects (recommended)
# This normalizes to LF in repository, converts to native on checkout
$ git config core.autocrlf input   # On macOS/Linux
$ git config core.autocrlf true    # On Windows

# Or use .gitattributes in the repository (better):
$ cat .gitattributes
# Set default behavior
* text=auto

# Explicitly declare text files
*.sh text eol=lf
*.py text eol=lf
*.md text eol=lf

# Declare binary files
*.png binary
*.jpg binary
*.pdf binary

# Windows batch files need CRLF
*.bat text eol=crlf

Fixing Line Endings in a Git Repository

# Normalize all text files in repository
$ git add --renormalize .
$ git commit -m "Normalize line endings"

ExFAT: The Universal Filesystem

When you need to share files via USB drives or SD cards, ExFAT is the best choice for cross-platform compatibility.

Why ExFAT?

FilesystemmacOSLinuxWindowsMax File Size
HFS+R/WRead*No8 EB
APFSR/WRead*No8 EB
NTFSReadR/WR/W16 TB
FAT32R/WR/WR/W4 GB
ExFATR/WR/WR/W16 EB

*With third-party tools

ExFAT is:

  • Native read/write on all three platforms
  • No 4GB file size limit (unlike FAT32)
  • Good for large external drives

Formatting as ExFAT

# Find disk identifier
$ diskutil list
/dev/disk4 (external, physical):
   #:                       TYPE NAME                    SIZE       IDENTIFIER
   0:     FDisk_partition_scheme                        *32.0 GB    disk4
   1:             Windows_FAT_32 UNTITLED                32.0 GB    disk4s1

# Format as ExFAT (WARNING: erases all data)
$ diskutil eraseDisk ExFAT SharedDrive /dev/disk4
Started erase on disk4
Unmounting disk
Creating the partition map
Waiting for partitions to activate
Formatting disk4s2 as ExFAT with name SharedDrive
Volume name      : SharedDrive
Partition offset : 411648 sectors (210763776 bytes)
Volume size      : 62078976 sectors (31784435712 bytes)
Bytes per sector : 512
Bytes per cluster: 32768
FAT offset       : 2048 sectors (1048576 bytes)
# FAT sectors    : 7680
Number of FATs   : 1
Cluster offset   : 9728 sectors (4980736 bytes)
# Clusters       : 969666
Volume Serial Number: XXXX-XXXX
Mounting disk
Finished erase on disk4

ExFAT Limitations on macOS

ExFAT on macOS has some restrictions:

# No extended attributes support
$ xattr -w user.test "value" /Volumes/SharedDrive/file.txt
xattr: file.txt: No such xattr: user.test

# No symbolic links
$ ln -s file.txt /Volumes/SharedDrive/link.txt
ln: /Volumes/SharedDrive/link.txt: Function not implemented

# No hard links
$ ln file.txt /Volumes/SharedDrive/hardlink.txt
ln: /Volumes/SharedDrive/hardlink.txt: Operation not supported

Network Share Considerations

When sharing files over the network, format differences still matter.

SMB Shares from Linux

When accessing Linux SMB (Samba) shares from macOS:

# Mount with specific options
$ mount_smbfs //user@server/share /mnt/share

# For better compatibility with Linux servers
$ mount_smbfs -o nounix //user@server/share /mnt/share

Common issues:

  • Permission mapping: Unix permissions don’t map perfectly to SMB
  • Case sensitivity: Linux share is case-sensitive; macOS client may cache incorrectly
  • Extended attributes: May not be preserved across SMB

NFS Shares

NFS is often more Unix-friendly:

# Mount NFS share
$ sudo mount -t nfs server:/export/share /mnt/share

# With specific options for Linux NFS servers
$ sudo mount -t nfs -o vers=3,resvport server:/export/share /mnt/share

See the Working with NFS and SMB chapter for detailed coverage.

Archive Formats for Cross-Platform Sharing

# Clean, cross-platform archive
$ xattr -rc folder/
$ COPYFILE_DISABLE=1 tar czf archive.tar.gz folder/

Alternative: zip Without macOS Extras

# Create clean zip
$ zip -r -X archive.zip folder/

# Exclude macOS metadata files
$ zip -r archive.zip folder/ -x "*.DS_Store" -x "*__MACOSX*" -x "*._*"

Receiving Archives from Other Systems

# Linux tar archives work fine on macOS
$ tar xzf linux-archive.tar.gz

# If you encounter extended attribute errors
$ tar xzf archive.tar.gz --no-xattrs 2>/dev/null

Practical Workflow: Syncing Project with Linux Server

A complete workflow for keeping a project in sync:

#!/bin/bash
# sync-to-server.sh - Sync project to Linux server cleanly

PROJECT_DIR="$HOME/projects/myapp"
REMOTE_HOST="dev@linux-server"
REMOTE_DIR="/home/dev/projects/myapp"

# Remove extended attributes
xattr -rc "$PROJECT_DIR"

# Sync with rsync, excluding macOS-specific files
rsync -avz --delete \
    --exclude='.DS_Store' \
    --exclude='._*' \
    --exclude='.AppleDouble' \
    --exclude='__MACOSX' \
    --exclude='.Spotlight-*' \
    --exclude='.Trashes' \
    --exclude='.fseventsd' \
    "$PROJECT_DIR/" \
    "$REMOTE_HOST:$REMOTE_DIR/"

Global Git Configuration

Configure Git globally for cross-platform work:

# ~/.gitconfig additions
$ cat >> ~/.gitconfig << 'EOF'

[core]
    # Handle line endings
    autocrlf = input

    # Warn about case issues
    ignoreCase = false

    # Ignore extended attribute changes
    ignoreStat = false

[transfer]
    # Stricter checking
    fsckObjects = true
EOF

Summary

IssueDetectionSolution
Case sensitivityfind . | sort -f | uniq -diUse case-sensitive volume or rename files
Extended attributesls -l@, xattr -lxattr -rc before sharing
AppleDouble filesfind . -name "._*"COPYFILE_DISABLE=1 or dot_clean
Line endingsfile command, cat -vdos2unix or configure .gitattributes
External drivesN/AFormat as ExFAT for universal compatibility

Key practices:

  1. Clean files before sharing: xattr -rc folder/
  2. Use clean archive creation: COPYFILE_DISABLE=1 tar czf
  3. Configure Git properly: .gitattributes with explicit line ending rules
  4. Test on target platform: Especially for case sensitivity issues
  5. Use ExFAT for shared drives: Works everywhere without drivers