We've all been there: you start a critical data_migration.py
script via SSH, then realize hours later you forgot to use screen
or nohup
. Now your terminal session is a single network hiccup away from disaster.
The fundamental limitation stems from Unix process hierarchy. When you start a process interactively:
$ python long_running_script.py
PID 1234
This process (PID 1234) becomes a child of your shell process (PID 1000). Closing the terminal sends SIGHUP to all children unless they're specifically detached.
1. reptyr - The Process Hijacker
The reptyr
tool can "steal" running processes:
# Install on Debian/Ubuntu
$ sudo apt install reptyr
# Find your target PID
$ ps aux | grep migration_script
# In a new screen session:
$ screen
$ reptyr 1234
Note: This requires ptrace_scope=0
in /etc/sysctl.d/10-ptrace.conf
2. gdb Debugger Method
For systems where reptyr
doesn't work:
$ gdb -p 1234
(gdb) call fork()
$1 = 5678 # New PID
(gdb) call setsid()
(gdb) continue
(gdb) detach
3. Using tmux's attach
If you have tmux
available:
$ tmux new -d 'reptyr 1234'
$ tmux attach
For future executions, consider these patterns:
# Using screen from start
$ screen -S migration
$ python script.py
Ctrl-A then D to detach
# Using nohup properly
$ nohup python script.py > migration.log 2>&1 &
Remember: Always test your persistence method with a dummy script before running critical jobs!
We've all been there - you start a long-running data migration script via SSH, then realize hours later you forgot to run it in screen
or with nohup
. Now you're stuck keeping your terminal open all night.
The fundamental limitation comes from how Unix process hierarchies work. When you start a process:
Terminal (PID 1000) → Shell (PID 1001) → Your Process (PID 1002)
Your process remains connected to the terminal through its parent process. Neither screen
nor nohup
can change this existing relationship - they only affect new processes.
Option 1: Reptyr - The Magic Tool
Install reptyr
(available in most package managers):
sudo apt-get install reptyr # Debian/Ubuntu sudo yum install reptyr # RHEL/CentOS
Then use it to steal your process:
# Start screen first screen # In another terminal, find your process ID ps aux | grep your_script # Attach it to screen reptyr PID
Option 2: GDB Debugger Method
For processes that resist reptyr:
# Attach gdb to the process gdb -p PID # In gdb: (gdb) call dup2(open("/dev/null", 0), 0) (gdb) call dup2(open("/dev/null", 1), 1) (gdb) call dup2(open("/dev/null", 2), 2) (gdb) detach (gdb) quit
This detaches the process from your terminal.
For future runs, consider these approaches:
# Using screen properly screen -S migration ./long_script.sh # Ctrl+A then D to detach # Using tmux (modern alternative) tmux new -s migration ./long_script.sh # Ctrl+B then D to detach # Using nohup correctly nohup ./long_script.sh > output.log 2>&1 &
If you can't use reptyr or gdb, your options are:
- Keep the terminal open (not ideal)
- Restart the process properly (if possible)
- Use SSH keepalives (temporary solution)