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)