Suppose you want to spawn a new interactive shell and provide an initial command to run. But it should still behave as if you typed the command yourself. For demonstration purposes let’s assume the command you want is just vim.
Turns out it’s not so easy. Bash doesn’t have a built-in option for that.
You might try the following:
vim; bash
On the surface, it works; you exit vim, you get to the interactive shell. But not quite: what you lose is job control. I want to be able to suspend vim (with Ctrl-Z) and get to the interactive shell. Obviously in this solution bash is not yet running, so it doesn’t work.
Next thing you might try is this:
bash --init-file <(echo 'source ~/.bashrc; vim')
This runs vim inside bash, so should be good; but it’s not. Job control doesn’t work during initialization.
Solution
We need to somehow make bash invoke our initial command after it executed the initialization file.
There’s a hook called PROMPT_COMMAND - it executes every time the shell wants to print a prompt (the hostname:~$ thing).
So we can run our startup command during the first prompt, and unset the hook so that it doesn’t trigger every time.
bash --init-file <(echo '
source ~/.bashrc
__startup() {
unset PROMPT_COMMAND
vim
}
PROMPT_COMMAND=__startup
')
Of course, this doesn’t work if your .bashrc already utilizes PROMPT_COMMAND for other purposes. Fixing this should be easy - an exercise for the reader.
Why would I use this?
For me it’s coding agents, of course.
I’d like some automation around starting new sessions (essentially to be able to spawn a subtask from another agentic session).
This would be a script that opens a new tmux tab with the coding agent (claude in my case).
However, I’m quite a heavy user of the suspend feature - to inspect the agent’s work from time to time. So I want to preserve the full interactiveness of the shell.