How to write bash output to arbitrary program stdi

2019-07-25 21:22发布

I want to (hopefully easily) write from a bash script to any arbitrary program that is already running via that program's stdin.

Say I have some arbitrary program "Sum", that constantly takes user input from the terminal. Every integer it receives from stdin it adds to the current sum and outputs the new sum. Here's example terminal text of what I mean:

$: ./Sum
Sum: 0
Give me an integer: 2
Sum: 2
Give me an integer: 5
Sum: 7

How would automate this process in a bash script? If I had control of Sum's source code I could let it accept integer arguments. But if I don't have said control of the program, how can I automate the interaction with Sum? Here's a psuedo code of a bash snippet of what I want to do:

In example.sh:

#!/bin/bash
my_program_input_point=./Sum &
echo 2 > my_program_input_point
echo 5 > my_program_input_point

Thus on my terminal screen it would still look like this:

$: ./example.sh
Sum: 0
Give me an integer: 2
Sum: 2
Give me an integer: 5
Sum: 7

The difference is I wouldn't have typed any of it.

It feels like this task should be really easy, because basically anything you can do in a terminal, you can also easily do in a script. Except, apparently, directly interact with an arbitrary process once its started.

This topic answers some aspects of my question by using pipes. However the accepted answer only works if I have control of both programs on each side of the pipe, the "recipient" program is under no obligation to read from the pipe automatically.

This is assuming I can't modify the program/script in question. I also can't write a "pipe reader" script to wrap around the program (Sum), because that wrapper script would still be required to interact with the running process Sum.

The second answer to this question on serverfault.com (written by jfgagne) seems much closer, but I can't seem to get it working. Is there any easier way to do this that I just don't know about?


For information on how to capture and read an arbitrary program's output, see my next question for more information

3条回答
Lonely孤独者°
2楼-- · 2019-07-25 21:53

The most straightforward way is to use a pipeline. The trick is that you can make the lefthand side of the pipeline a compound statement, or a function call. It doesn't have to be just a single command.

{
    echo 2
    echo 5
} | ./Sum

or

numbers() {
    echo 2
    echo 5
}

numbers | ./Sum

This lets you do whatever you want to generate the input. You don't have to have it all ahead of time. If you generate the input bit by bit, it'll be fed to ./Sum bit by bit.

查看更多
够拽才男人
3楼-- · 2019-07-25 21:55

You can use a named pipe. Whatever starts Sum is responsible for creating the named pipe some place convenient, then starting Sum with the named pipe as its standard input.

mkfifo /tmp/pipe
Sum < /tmp/pipe

Then your script could take the name of the pipe as an argument, then treat it as a file it can write to.

#!/bin/bash
p=$1

echo 2 > "$p"
echo 5 > "$p"

Then you could call your script with client /tmp/pipe.

查看更多
劫难
4楼-- · 2019-07-25 21:55

You can write to the standard input file descriptor of the running process. Here is the same question: https://serverfault.com/questions/178457/can-i-send-some-text-to-the-stdin-of-an-active-process-running-in-a-screen-sessi

You need to write to /proc/*pid of the program*/fd/0 which is the file descriptor for the standard input of the process with that pid. Make sure you have access to do this.

查看更多
登录 后发表回答