GNU shred: In-Place Overwrites and the Limits of File Erasure
Understand what GNU shred writes, what its options change, and why filesystems, flash translation layers, snapshots, and backups can preserve data.
shred is often described as a command that securely deletes a file. That shorthand hides the important condition in GNU’s own documentation: the utility can only overwrite the data that the filesystem and storage device expose as the file’s current contents. It cannot know whether the old blocks were replaced in place, retained in a snapshot, copied to a backup, remapped by a flash controller, or cached by another layer. A successful exit status says that the requested operations completed through the operating-system interface; it does not prove that every physical copy became unrecoverable.
This article refers specifically to GNU Coreutils 9.12’s versioned source and Texinfo documentation. It does not describe a POSIX command, nor should its options or behavior be assumed for a similarly named program on another operating system.
What the command actually requests
GNU shred FILE opens the named file and repeatedly writes replacement data over its apparent contents. In Coreutils 9.12, the default is three overwrite passes. -n N or --iterations=N changes that number. -z or --zero adds a final pass of zeros, mainly to make the finished contents look less obviously overwritten. That cosmetic pass is not an erasure proof and does not address data retained outside the live file mapping.
By default, GNU shred does not remove the file after overwriting it. -u or --remove asks it to deallocate and remove the named entry after the overwrite. --remove=unlink uses a normal unlink operation; wipe also obfuscates filename bytes; and wipesync syncs those obfuscated name bytes as it works. These filename options concern the directory entry, not hidden copies of file data. If the file has multiple hard links, removing one name does not remove the other names. If a process already has the inode open, unlinking a directory entry does not itself revoke that open handle.
For a regular file, the default behavior rounds the size up to a filesystem block boundary to cover the unused tail of the final block. --exact suppresses that rounding and leaves the apparent size unchanged. --size=BYTES limits the operation to the requested prefix. Those controls change the byte range or resulting file size; they do not make an unsupported filesystem overwrite in place. Be especially cautious about reducing a file’s size or specifying only a prefix when the goal is to eliminate all earlier contents.
If you are learning the command, test its visible behavior only on a disposable file in a scratch directory:
shred --verbose --iterations=1 --zero ./throwaway-test-file
This example deliberately leaves the file present so you can inspect its resulting size and contents. Do not substitute a real path from a production, home, or shared directory while experimenting. A --remove invocation can make a mistake harder to notice and recover from; neither verbose progress nor post-operation readback can establish physical-media erasure.
The in-place assumption is the critical boundary
Overwriting a pathname is not the same thing as addressing a fixed set of physical blocks. GNU’s manual explicitly cautions that shred assumes both the filesystem and hardware overwrite in place, an assumption that many modern designs do not satisfy. The manual lists journaled or log-structured modes, copy-on-write or snapshot-capable arrangements, redundant storage, network caches, and compressed filesystems among relevant exceptions. A new version of a file can be written to new blocks while an older version remains reachable through a snapshot, journal, replica, or backup.
This is why filesystem names alone are not always enough. Mount mode, copy-on-write features, snapshot policy, network client behavior, storage virtualization, and the path from host block device to physical media all matter. A virtual machine may write to a virtual disk image that is itself snapshotted or backed up. A file in a synchronized folder may already have been copied to a remote service. A database or editor may have written temporary, journal, or autosave copies before shred ever received the path.
The limitation also applies when targeting a device file. GNU notes that solid-state devices use wear leveling, which can direct writes to different underlying blocks, and that storage can remap bad blocks outside the operating system’s view. These mechanisms can leave earlier data beyond the address range the command can reach. Writing repeated passes to a device therefore does not bypass the device’s firmware, controller, hidden reserve area, or prior copies.
The number of passes is not a substitute for knowing the storage model. Coreutils documents the historical default patterns and says a single pass should suffice for newer devices, but that statement is conditional on the basic overwrite model. Adding passes cannot fix copy-on-write snapshots, backups, or controller remapping. It usually increases I/O time and device writes without changing the underlying boundary.
Choose the operation that matches the storage boundary
Before relying on shred, identify the data lifecycle rather than starting with a pass count:
- Name the scope. Is the target one ordinary file, a set of hard links, a mounted filesystem, a VM image, a shared folder, or an entire storage device?
shreddoes not recursively discover every copy associated with a pathname. - Map the layers. Record the filesystem type and options, snapshot/replica policy, backup destinations, virtualization layer, and device type. If any layer’s write behavior is unknown, GNU’s manual recommends assuming that regular-file overwrites are unreliable there.
- Protect the source of truth. If data must remain recoverable until a deletion request is authorized, first complete the approved retention and backup review.
shredis destructive to the live target; it is not a replacement for retention controls or access revocation. - Select a documented sanitization method. For modern SSDs, managed arrays, cloud volumes, and encrypted devices, use the storage or service provider’s documented sanitize, crypto-erase, key-retirement, or retention workflow where applicable. Confirm its scope and completion evidence; do not treat a generic pathname write as equivalent.
- Test observability separately from efficacy. A scratch-file run can confirm that the installed GNU binary parses the options and writes the expected visible result. It cannot demonstrate that a storage controller removed remapped sectors or that a snapshot no longer holds an old version.
For the strongest operational record, capture the exact shred --version, command line, target identity, filesystem and mount configuration, device/service type, run status, and the separate control used for snapshots and backups. Store the record without copying sensitive file content into logs. A zero exit status should be reported as “the requested overwrite command completed,” not “the data is impossible to recover.”
Keep snapshots, replicas, and backups in scope. GNU specifically warns that file backups and remote mirrors may retain recoverable copies even when the live file was overwritten or its directory entry removed. Those systems have their own retention and deletion semantics; process them through their supported lifecycle and legal/organizational retention requirements. Do not erase a backup set or shared device as a side effect without confirming its ownership and retention boundary.
shred is a useful low-level overwrite utility only when the system’s storage behavior matches its assumptions and all relevant copies are accounted for. On an unknown filesystem or modern managed storage, it is not a reliable proof of secure deletion. The safe conclusion is deliberately narrower: the command can request repeated writes through the file or device interface, and the storage stack determines what those writes replace.
Related:
- sed In-Place Editing: Portability, Backups, and Safe File Replacement
- sync in Shell Scripts: Writeback Is Not a Transaction or a Backup
Sources: