Cause #1: The file is currently running as a process
That's the whole ballgame right there. The Linux kernel won't let you write to a file that's currently being executed. It's a safety thing — if you could overwrite a running binary, the process could crash or execute garbage mid-run. The kernel returns ETXTBSY (Errno 26) to stop that.
You'll see this most often when you're recompiling a program and trying to cp or mv the new binary over the old one while it's running. Also happens with shell scripts you're editing and trying to overwrite with cat > script.sh while the script runs in another terminal.
The fix: Stop the process first, then overwrite
# Find the process using the file
lsof /usr/local/bin/myapp
# or
ps aux | grep myapp
# Kill it (use SIGTERM first, escalate to SIGKILL if needed)
kill <PID>
# or
pkill myapp
# Now overwrite works fine
cp newapp /usr/local/bin/myapp
Don't bother with chmod +x or changing ownership — that won't help. The kernel doesn't care about permissions here. It's purely about the file being mapped into an executing process's memory.
Pro tip: If it's a critical service like nginx or sshd, use the service's restart command instead of killing blindly:
sudo systemctl restart nginx
Cause #2: You're trying to overwrite a running script with a redirect
This one gets people all the time, especially with automation. You have a script running, and part of it tries to write to itself:
#!/bin/bash
# This will fail with 'text file busy'
echo "Log entry" >> /path/to/script.sh
Or you're doing something like ./script.sh > script.sh to truncate the file while it's executing. That's a one-way ticket to ETXTBSY.
The fix: Redirect to a temp file then rename
Write to a different file and then mv it into place — but only after the script has finished. Or just don't do that. If you need to append logs, put them in a separate log file, not the script itself.
# Instead of overwriting the running script, write to a temp file
echo "Update" > /tmp/script_update
# Then wait for the script to stop, or schedule the move with cron
mv /tmp/script_update /path/to/script.sh
Real-world trigger: I've seen cron jobs that update their own script at the end of execution. That's fine — the process has already exited by then. But if you run the script manually in the foreground and it tries to modify itself mid-run, boom. That's ETXTBSY.
Cause #3: The file is open by another program (rare for ETXTBSY)
Technically, ETXTBSY is about execution, not just opening. But there's a corner case: if you have a file open for writing and try to execute it, some systems will return ETXTBSY. This is more common with interpreted scripts where the interpreter has the file open.
Example: you're editing a Python script in vim, and from another shell you try to run it. Vim has the file open for writing (not executing), but the kernel might still block execution. That's not standard Linux behavior, but it happens on some NFS mounts or with certain filesystems.
The fix: Close the editor or use a different approach
Save the file and close vim before running it. Or better: use vim -c ':wq' in a non-interactive way. Also, if you're on NFS, try moving the file locally first.
# On NFS, copy to local disk, edit, then copy back
cp /mnt/nfs/script.sh /tmp/script.sh
echo "change" >> /tmp/script.sh
cp /tmp/script.sh /mnt/nfs/script.sh
The nuclear option: the install command
There's a cleaner way to replace a running binary without hitting ETXTBSY most of the time: use install. It copies to a temp file and then renames it, which avoids the write-to-running-file problem.
sudo install -m 755 newapp /usr/local/bin/myapp
This works because install creates a new inode and atomically replaces the old one. The running process still has its old inode mapped, so it keeps running fine. New processes pick up the new file. That's the kind of trick you'll appreciate after you've had to restart a service mid-deploy.
Quick reference summary
| Trigger | Fix |
|---|---|
| Overwriting a running binary | Kill the process, then copy |
| Script writing to itself | Use a temp file and rename after exit |
| File open in editor while executing | Close the editor, or edit then run |
| Any situation where you can't stop the process | Use install or mv instead of cp |
One more thing: if you see ETXTBSY on a file that isn't running, check if it's on a weird filesystem like FUSE or a network mount. Sometimes the kernel gets it wrong. But 99% of the time, it's a running process. Don't overthink it.