Check desired state instead of remembering past actions: a rerun that
prints only [=] is proof of convergence. Real files are kept once as
*.backup; a missing source never creates a dangling link. Pairs with
marker output.
link() { src="$1" dst="$2" [ -e "$src" ] || { warn "$src missing, skipped"; return 0; } [ "$(readlink "$dst" 2>/dev/null)" = "$src" ] && { skip "$dst"; return 0; } if [ -e "$dst" ] && [ ! -L "$dst" ]; then mv "$dst" "$dst.backup" warn "kept old file as $dst.backup" fi mkdir -p "$(dirname "$dst")" ln -sfn "$src" "$dst" ok "linked $dst"}