4

In Bash 4.X It it possible to do something like:

command that expects input &
echo some output | %1

Where %1 represents the first backgrounded command?

  • 1
    Is there a reason why you don't just do echo some output | command that expects input &? – terdon Jul 18 '13 at 18:25
  • 1
    It was a hypothetical question that came to my mind when thinking about ; for instance; doing rm -i * on a dir with tons of files, and wanting to then just change the command to yes|rm -i, for example. – Gregg Leventhal Jul 18 '13 at 18:34
  • I still don't understand the point. The example you gave expects no input. If a command expects input there is no point in launching it before that input is available. In any case, hypothetical questions are off topic. – terdon Jul 18 '13 at 18:36
  • This question appears to be off-topic because it is about a hypothetical situation and not a specific problem. – terdon Jul 18 '13 at 18:37
  • rm -i will expect a y or n for every file passed to it. I am talking about (in this example) using the yes command to simply answer y to every prompt that gets generated by the rm command. It really isn't so hard to understand, is it? – Gregg Leventhal Jul 18 '13 at 18:52
3

Once you start:

rm -i -- * &

rm has been started with whatever stdin was in your shell at the time you invoked that command.

If it was the terminal, then rm will typically be suspended (with the SIGTTIN signal) as soon as it tried to read from it (since it's not in the foreground process group of the terminal).

If you want it to read from something else, you have to tell it to reopen its file descriptor 0 on something else.

You could do that with a debugger (here assuming you're on Linux):

rm_pid=$!
coproc yes
gdb --pid="$rm_pid" --batch \
    -ex "call close(0)" \
    -ex "call open(\"/proc/$$/fd/$COPROC\", 0)" /bin/rm
kill -s CONT "$rm_pid"

Above, we're starting yes in background with its stdin and stdout redirected to a pipe. The other end of that pipe is in the shell (process $$) on file descriptor ${COPROC[0]} aka $COPROC.

Then, with gdb, we're telling rm to close its fd 0, and reopen it on that same pipe.

  • 1
    This is some true wizardry. – Snowball Sep 27 '14 at 5:36
  • After a long time, I switched to this incredible answer because yours was far superior to the previously selected one. Thanks Stephane, you always have amazing answers. – Gregg Leventhal Apr 21 '16 at 16:59
5

Yes, but you need a little bit more.

When you send a program to the background you're detaching it from stdin associated with your terminal. You need to start it up instead with an alternate input, in this case a pipe.

$ mkfifo alternate_input
$ command_that_expects_input < alternate_input

You've now assigned the pipe file (alternate_input) as the stdin for the process command_that_expects_input. To send input, simply put something into the pipe.

$ echo foo > alternate_input

In this case the string foo becomes is transferred to stdin for command_that_expects_input.

  • Excellent, this is a good solution. – Gregg Leventhal Jul 23 '13 at 21:17
  • @gleventhal: if this better answers your question you should select it for posterity. – bahamat Jul 25 '13 at 8:54
  • Done. The one thing missing from your answer is exactly how I should take the job from the background and perform redirection on it. Mind specifying how to do so? – Gregg Leventhal Jul 25 '13 at 18:05
  • You have to do the redirection before it goes to the background, or you can program it to open a predetermined stdin. – bahamat Jul 25 '13 at 21:10
  • The point of the question was how to do it retroactively though. – Gregg Leventhal Jul 26 '13 at 15:42
1

The way you postulate, no. As terdon says, it's much easier if you know you need to pipe input in the first place. In the rare (so rare I've never encountered it) case where a program expects no input now but will expect input in the future, you can set up a named pipe as the input to that process, background it, then send output of a later-started process to the same named pipe, but you have to set the named pipe up beforehand.

  • Thanks. I was more thinking of a situation where you set a flag to prompt, or forgot to set a flag to not prompt (i.e. rm -i or yum without -y) and wanted to retroactively change that. – Gregg Leventhal Jul 18 '13 at 18:56
  • There's no way to do that. Rather, the only want to do that is to kill and restart the process with the flag you meant to set. – John Jul 18 '13 at 19:00

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.