I put two files in one directory. Both appeared as café.txt in my terminal.
They were not aliases or links. Each file had its own inode, its own contents, and its own checksum. One said composed filename; the other said decomposed filename.
This is less a Linux trick than a disagreement over what counts as the same text.
One accent, two recipes
The first filename used the single Unicode character é, U+00E9. The second used an ordinary e, U+0065, followed by a combining acute accent, U+0301. Most fonts stack the second recipe into the same visible letter as the first.
The Unicode standard calls these forms canonically equivalent. They represent the same abstract text and should have the same appearance, but their underlying sequences differ. In UTF-8, the composed filename occupied nine bytes:
63 61 66 c3 a9 2e 74 78 74
The decomposed version needed ten:
63 61 66 65 cc 81 2e 74 78 74
My local Linux filesystem accepted both byte sequences as separate directory entries. A directory listing showed two copies of café.txt, distinguished only by which line came first. That is a fairly mean interface for a distinction no human asked to manage. Even a log or approval screen can hide which file is about to be replaced.
The ZIP file kept the disagreement
I put both files into one ZIP archive. Python reported two entries, and each retained its original byte sequence. Nothing in that trip decided that the names meant the same thing.
Then I applied Unicode's NFC normalization to both names. NFC decomposes text canonically and then composes characters where it can. After that operation, both filenames became the same sequence. Python exposes this directly as unicodedata.normalize():
from unicodedata import normalize
first = "caf\u00e9.txt"
second = "cafe\u0301.txt"
print(first == second) # False
print(normalize("NFC", first) ==
normalize("NFC", second)) # True
That creates a practical problem. A system can accept two uploads as distinct, move them somewhere that treats equivalent names as equal, and discover a collision only after it has promised to preserve both.
Different systems make different promises
This behavior is not portable. Apple's archived APFS documentation describes the filesystem as normalization-insensitive: it preserves the entered form but prevents equivalent variants from coexisting in one directory. Microsoft documents Windows file APIs as treating names as opaque sequences of WCHAR values and leaves any normalization an application needs outside the filesystem call.
Applications, frameworks, archive tools, network shares, and filesystems can therefore meet the same name with different ideas about equality. The trouble usually appears at a boundary: upload, extraction, synchronization, or a move between machines.
A cautious file pipeline chooses a normalization policy before checking for duplicate names, detects collisions after normalization, and keeps the original display name separately if it matters. NFC is a common choice for preserving canonical meaning. The more aggressive compatibility forms, NFKC and NFKD, can erase distinctions such as superscripts and width variants, so they should not be applied to arbitrary names just because their initials look official.
Normalization also does not solve every lookalike problem. A Latin a and a Cyrillic а are different characters, not two canonical forms of one character. That is another trap with a similar costume.
My two files were tiny and harmless. The useful result was the collision: before normalization, the computer had two names and my eyes had one. After normalization, they finally agreed, but there was only room for one file.