16

I'm trying to run an app (let's say top) so it will read from a file for stdin and write to another file from stdout.

Currently I have

mkfifo stdin.pipe
(tail -f stdin.pipe) | top

which works as expected, as I can then echo something to that file and top will receive it. But I'm unable to redirect the output of top. How can I achieve this?

EDIT:

Ok, let's scratch top. I'm testing with this:

cat test.sh

echo Say something
read something
echo you said $something
alexandernst
  • 14,352
  • 22
  • 97
  • 197
  • Are you sure `top` reads from `stdin`? Mine doesn't. You can redirect output from `top` using the `-b` (batch) option: `top -n 1 -b > gash` – cdarke Mar 28 '13 at 11:35
  • @cdarke I'm sorry, you're right. I was making tests with another app. top doesn't work the same way. Is there a way I can map stdin and stdout to files and use them to control a cli app? – alexandernst Mar 28 '13 at 11:38

2 Answers2

50

Let's forget about top, that appears to be a red herring.

To map stdin or stdout to files, you can use redirection:

some_program < input_file          # Redirects stdin

another_program > output_file      # Redirects stdout

or even:

yet_another  < input_file > output_file
cdarke
  • 42,728
  • 8
  • 80
  • 84
  • Is this async or sync? I just tested it with a 2 lines bash that will say "Hi", wait for input and then say "Bye". I was able to see the output in the output_file after I redirected something to the input_file (aka, when the app finished running) – alexandernst Mar 28 '13 at 11:48
  • If you are commuicating between programs then use an anonymous pipe, it will be more efficient than using a temporary file. Depends what you mean by sync/async in this context, but all shell IO is buffered. The buffer is flushed and the file is closed after each redirection, but you can get issues if a program is reading while one is writing (to a file, not a pipe). – cdarke Mar 28 '13 at 13:23
  • The problem is that I'm trying to control a CLI app from PHP so I can't save the handle to the pipe, that's why I need to be able to read/write to/from files. How can I force output to be flushed instead of going to buffer? – alexandernst Mar 29 '13 at 02:33
  • Use a named pipe instead of a file, you can redirect to a named pipe just as if it was a file (um, actually, it is a file). You can also read a named pipe from PHP just as if it was a text file. – cdarke Mar 29 '13 at 12:46
  • are you sure that this will work with the example script I posted in my question? (the edit part). I just created mkfifo ```in``` and ```out``` and I ran my script. I expected to get ```Say something``` after ```cat out``` but I didn't get anything. – alexandernst Mar 29 '13 at 13:44
  • How to take input until reaches the end of the file and then come out of script automatically. I am in infinite loop and it does not come out of loop when EOF reached. – Windy Day Sep 11 '18 at 09:25
8

Is there a way I can map stdin and stdout to files and use them to control a cli app?

It sounds like you are looking for coprocesses, added to Bash in 4.0.

coproc cat                    # Start cat in background
echo Hello >&${COPROC[1]}     # Say "Hello" to cat
read LINE <&${COPROC[0]}      # Read response
echo $LINE                    # cat replied "Hello"!

Before 4.0 you had to use two named pipes to achieve this.

Joni
  • 108,737
  • 14
  • 143
  • 193