verifyfirst

The file's contents · edit-replaces-the-link-not-the-target · documented

An in-place edit of a symlink replaces the link with a regular file

NS-083 documentededit-replaces-the-link-not-the-target

An in-place edit of a symlink replaces the link with a regular file

reads as
`sed -i 's/old/new/' app.conf` exits zero and reading app.conf shows the new value. Conclusion drawn: the configuration was updated.
actually
GNU sed edits in place by writing a temporary file and renaming it over the target, and it does not resolve symbolic links unless asked; the existence of `--follow-symlinks`, documented as following symlinks when processing in place, is the acknowledgement. The rename replaces the link itself. The path now holds a regular file carrying the new content, the file the link pointed at is untouched, and the link no longer exists.
blind because
Reading the path returns the edited content, because the path genuinely holds it now. What changed is the identity of the object behind the name, and content is the one thing that cannot reveal it.
the check
Look at the type and inode behind the name rather than at the bytes: `stat -c '%i %F %N' app.conf`. Observed on GNU sed 4.9 with app.conf a symlink to repo/app.conf: beforehand `2659981 symbolic link 'app.conf' -> 'repo/app.conf'`; after `sed -i`, `2659983 regular file 'app.conf'` holding `setting=new`, while repo/app.conf still held `setting=old` at its original inode 2659980. With `--follow-symlinks` the link survived and repo/app.conf received the edit.
cost of missing
The change is invisible to the repository the link came from, is not committed, and is silently reverted the next time the link farm is rebuilt or the host is reprovisioned. Meanwhile every other path sharing the original inode still serves the old value.
mitigation
`sed -i --follow-symlinks`, or edit the resolved path from `readlink -f`. The same applies to any tool that writes by rename.
generalises to
Every write-by-rename: editors saving atomically, `sed -i`, `sort -o`, dotfile farms, hard links and bind mounts that expected to keep sharing an inode.
source
man7.org

Reported as

Others this instrument misses

plain text · full registry