~/adi
TIL: Killing an scp loop
Story
Yesterday I fired off a quick loop to pull down some files from a server:
for f in $(cat file-list.txt); do
scp user@hostname:path/to/data/$(basename $f) local_dir/
done
I just needed a couple of examples1 so I decided to kill the command when I had them.
When I closed the shell, I expected everything to stop—but the downloads kept chugging away.
I ran ps aux | grep '[s]cp'
and tried kill $PID
, but got “no such process.”
Opening htop
, I saw the scp
process but by the time I grabbed it’s PID, it had finished.
I traced the parent with:
ps -o pid,ppid,command -p $(ps aux | grep '[s]cp' | awk '{print $2}')
Examining the parent showed it was /bin/zsh
, so I killed that, but the downloads continued.
I traced the grandparent and found it to be login
, which worried me because killing that would log me out.
How was this possible?
htop
has a nice Tree feature. This is the tree I was climbing:
├─ /Applications/Ghostty.app/Contents/MacOS/ghostty
│ ├─ login
│ │ └─ -/bin/zsh
│ │ └─ scp
So I quit my terminal app (Ghostty.app), and the downloads stopped.
Learnings
One-liner for fast-moving processes Quickly inspect PID, PPID, command for processes that vanish too fast to track:
ps -o pid,ppid,command -p $(ps aux | grep '[s]cp' | awk '{print $2}')
htop’s tree mode makes it easy to inspect and kill at the right level of the process tree.
ctrl-D exiting a tab in Ghostty might leave things running as the shell integration by default may not always detect background processes and loops when closing tabs. There are a number of settings to improve this e.g.
shell-integration = zsh
quit-after-last-window-closed = true
wait-after-command = true
Quitting the app should clean these up, as all processes are nested under ghostty
.
Footnotes
That’s what
head
is for? Yeah, I know, I know.↩︎
© 2025 Adi Mukherjee. Credits.