I have been plagued by a bug I see often in Terminal. I know it’s been at least months, and it may have even been years. But it’s gotten worse lately. I call it the “phantom [Process Completed] bug.” The symptoms of this issue are that every so often an innocent attempt to open a new Terminal window instead yields an immediate “[Process Completed]”. What this has meant for me is that I’ve basically gotten used to “trying again” whenever I see this. It sucks though, because it limits my ability to automate with confidence when it comes to opening new shell windows. The thing about this bug is seems to “happen only every other time per pseudo-tty.” So if it fails once, it will probably not fail the very next time you try it! A dangerous recipe for “acceptance,” but this is a terrible concession to have to make to a computer!
Things finally came to a head today and I decided to track down the root cause. I posted to the MacOSX-Dev mailing list for help, and Chad Leigh pointed me in the direction of some very helpful advice that, while it alleviates a separate problem I was experiencing (running out of processes, and getting fork failures), it doesn’t solve the “Process Completed” problem.
I needed to collect some hard data, so I started out by rebooting my machine. On a freshly booted machine, I am able to create a dozen new Terminal windows without running into the problem a single time. Close those dozen windows and try again, and about half of them fail! So this has something to do with reusing pseudo-TTYs? I decided to switch over to “iTerm” for a little comparison. Sure enough, opening a dozen windows there yields about the same failure rate.
I searched the web (again, I had tried this months ago), and came up with some interesting leads. Some people have noticed that the problem is worse with zsh. I run zsh, lucky me! Other people have noticed that the problem only happens when a Terminal window is closed without manually closing down the shell inside first. Sure enough, I almost always close my shells with Cmd-W, allowing Terminal to “take out the trash.” I run some more tests, and what do you know? I can “cleanse” ttys by making sure that I run “exit” on the shell before closing the window.
Since the rumor is that it happens more in zsh than other shells, I’m inclined to believe it’s a shell bug. I decide to test against a very simple shell: “bc” the built in UNIX calculator. Setting my default shell to “/usr/bin/bc”, I go on a rampage of opening a dozen or more new shells, closing them all, and trying again. Sure enough, “bc” is completely clean. It can take a beating and happily reopen on the same old tty that got slammed last time-around. I switch back to zsh, and open a bunch of terminals again. They’re all clean! So bc left them clean enough for zsh’s liking. It must be something about the way zsh “takes out the trash” (or doesn’t).
I switch the default shell to “/bin/sh”. In twelve opens, I witness the failures due to booby-traps set by zsh. Close twelve. Open twelve again: all clean. Sh (bash, actually) cleans up well! Try with tcsh: all clean, too!
Damn you zsh! I love ya, but you’re a messy sucker!
I’m not about to give up zsh, and I’m not quite ready to look into locating the bug in zsh, but I need to work around this. I know that if I type “exit” every time I need to close a shell window, I will never see the bug again, but I’m too lazy to remember to do that! FastScripts/AppleScript tag team to the rescue. I wrote this simple script:
do script "exit" in window 1
close window 1
With FastScripts I’m able to override just about any menu shortcut in just about any app, so I set it up as an Terminal-specific script, and assign it the shortcut Cmd-W. Now, whenever I type Cmd-W in Terminal, the same shortcut I’ve been using for years to close shell sessions, the Terminal first performs an explicit “exit” in the window, and then closes it. I get to keep my behavior, but the buggy zsh conditions are no longer produced.
I’m so excited by this that I’ve spent a few minutes just holding Cmd-N down for several seconds, closing all the windows, and repeating. Ah, it’s going to be a nice autumn.
Update: I thought I had observed some funkiness with the state of the pseudo tty files after zsh was closed on them, but I’ve come to find out that the behavior is not unique to zsh. I think it’s a red herring. Other shells sometimes leave the tty in this funky state and it doesn’t seem to affect their ability to reopen the tty as a healthy session.
Update 2: It occurred to me that one of the downsides to replacing Cmd-W with a scripted keyboard shortcut is that I can’t take advantage of the “hold down the keys for repeated invocation” functionality that you normally get for free with menu items.
I decided the only reason I was taking advantage of this in Terminal is because it lacks a proper “Close All” function. So, I wrote another script, this one mapped to Cmd-Opt-W in Terminal, which will first go through and call “exit” in all the open windows, and then close them all:
return count of windows
if ((count of windows) is equal to 0) then
repeat with thisWindowNumber from 1 to (count of windows)
do script "exit" in window thisWindowNumber
repeat count of windows times
close window 1