Run command in background with foreground terminal access
10
votes
4
answers
6033
views
I am trying to create a function that can run an arbitrary command, interact with the child process (specifics omitted), and then wait for it to exit. If successful, typing
run
will appear to behave just like a bare ``.
If I weren't interacting with the child process I would simply write:
run() {
"$@"
}
But because I need to interact with it while it runs, I have this more complicated setup with coproc
and wait
.
run() {
exec {in}&1 {err}>&2
{ coproc "$@" 0&$out 2>&$err; } 2>/dev/null
exec {in}&- {err}>&-
# while child running:
# status/signal/exchange data with child process
wait
}
(This is a simplification. While the coproc
and all the redirections aren't really doing anything useful here that "$@" &
couldn't do, I need them all in my real program.)
The "$@"
command could be anything. The function I have works with run ls
and run make
and the like, but it fails when I do run vim
. It fails, I presume, because Vim detects that it is a background process and doesn't have terminal access, so instead of popping up an edit window it suspends itself. I want to fix it so Vim behaves normally.
**How can I make coproc "$@"
run in the "foreground" and the parent shell become the "background"?** The "interact with child" part neither reads from nor writes to the terminal, so I don't need it to run in the foreground. I'm happy to hand over control of the tty to the coprocess.
It is important for what I'm doing that run()
be in the parent process and "$@"
be in its child. I can't swap those roles. But I *can* swap the foreground and background. (I just don't know how to.)
Note that I am not looking for a Vim-specific solution. And I would prefer to avoid pseudo-ttys. My ideal solution would work equally well when stdin and stdout are connected to a tty, to pipes, or are redirected from files:
run echo foo # should print "foo"
echo foo | run sed 's/foo/bar/' | cat # should print "bar"
run vim # should open vim normally
---
> Why using coprocesses?
I could have written the question without coproc, with just
run() { "$@" & wait; }
I get the same behavior with just &
. But in my use case I am using the FIFO coproc sets up and I thought it best not to oversimplify the question in case there's a difference between cmd &
and coproc cmd
.
> Why avoiding ptys?
run()
could be used in an automated context. If it's used in a pipeline or with redirections then there wouldn't be any terminal to emulate; setting up a pty would be a mistake.
> Why not using expect?
I'm not trying to automate vim, send it any input or anything like that.
Asked by John Kugelman
(2087 rep)
Mar 21, 2019, 05:54 PM
Last activity: Mar 31, 2019, 06:29 PM
Last activity: Mar 31, 2019, 06:29 PM