1

I have a little program, let's call it "program" by simplicity which has "normal" behaviour. It takes information from the stdin (normally typed in by the user in the keyboard) and prints out via stdout/stderr. I want to automate a process and therefore redirect stdout/stderr into "my little bash script" (which could also be another program in C/C++). It takes it as it's standard input and filters it. This means leaving out unimportant information.. and adding further information generated by the bash script itself. The output is shown on the sreen (printed out by the echo command).

This is working so far:

program --verbose 2>&1 | ./mylittlebashscript.sh

Scheme:

 stdin     +---------------+              +---------------+
 --------->|               |--stdout--+-->|      my       |-->screen
           |    program    |          |   |    little     |
           |               |--stderr--|   |  bash script  |
           +---------------+              +---------------+

Now I want to go one step further: The program expects input from the user which I want to give automatically by my little bash script. For example it prompts the user to enter the path to a specific file. The path is known by my little bash script and the bash script knows when the program is waiting for input (as the last line being printed out contains something which is "greped"). How can I pipe back some information out of my bash script? I do not want to pipe back all the stdout because several information only needs to be displayed on the screen and the program would not like this output.

New scheme:

 (stdin?)  +---------------+              +---------------+   (stdout?)
 -------+->|               |--stdout--+-->|      my       |-->screen
        |  |    program    |          |   |    little     |
        |  |               |--stderr--+   |  bash script  |----+(maybe
        |  +---------------+              +---------------+    | stderr?)
        |                                                      |
        +------------------------------------------------------+

At the moment I am not very familiar with Linux yet. I guess there is a possibility working with cat, fifos, tee and pipes/redirections. Unfortunately I haven't brought it to life so far.

I'd really be happy about a little example! Thank you very much!

Cheers Matthias

PS: I think this thread is related: how to redirect stdout of 2nd process back to stdin of 1st process?

Edit: Ok, for fruther explanation I took my test files from my test machine:

I replaced "program" by another batch file called input.sh:

#!/bin/bash
echo "input.sh: give me input, waiting for input 1"
read x
echo $x
echo "input.sh: give me input, waiting for input 2"
read x
echo $x

And I got a second one ("mylittlebashscript.sh"), now called inter.sh to process:

#!/bin/bash
echo "inter.sh: start"
while read line ; do
  echo "inter.sh: line>$line"
  notfound=$(echo $line | grep "waiting")
  if [[ "$notfound" ]]; then
    echo "inter.sh: input sh seems to wait for input! putting something in the fifo"
    #echo "banana" > testfile
    #echo "I am the stderr" >&2
  fi

done
echo "inter.sh: end"
exit
Community
  • 1
  • 1
matthias
  • 247
  • 6
  • 17

6 Answers6

3

Did you try, as an answer the thread you linked states:

mkfifo fifo
program --verbose < fifo 2>&1 | ./mylittlebashscript.sh | tee fifo

?

Maybe, you should make your script print out some text before waiting for input, in order to avoid getting stuck in a waiting loop..

redShadow
  • 6,687
  • 2
  • 31
  • 34
  • Thank you for the hint. Unfortunately I did not get this working. I edited my post with my two test files. I think in your example I also put everything I echo back to the stdin of "program" (if it was working). But the thing is.. I want to bring something on the screen... and something else back to the stdin of "program". Maybe I can put something in stdout and somethin in stderr? Thanks! – matthias Jul 21 '11 at 10:57
  • What I have now is: `./input.sh < fifo 2&>1 | ./inter.sh 2>fifo` I think I am coming closer! :D – matthias Jul 21 '11 at 11:59
  • Ok, so this also does not work for me; only in the small .sh example it does. It seems the fifo is just immediately read after the program has printed out the line.. and takes some old(??) content or empty content to continue. Or maybe some called programm writes to stderr in my batch file? I also tried something like this: `./input.sh < fifo 2&>1 | ./inter.sh 2>/dev/null` and `echo "foobar" >&fifo` in my shell script. This also does not work.. afterwards `cat fifo` gives me the right output. Is there btw an option to manually flash the buffer? Would not have thought this was not trivial... – matthias Jul 21 '11 at 13:09
3

An additional expect-like software tool would be empty!

http://empty.sourceforge.net

markus
  • 46
  • 1
  • Looks interesting. Do you use it? Unfortunately I could not find a manpage for it. I'd like to know what the command line arguments like f, w and s are for. It's hard to find good results on search engines when you only enter "empty" and "script", "manual" or something. But thanks so far! – matthias Jul 25 '11 at 13:36
  • Okay, just typing "empty" prints the usage -- which is still quite cryptic to me. I have tried to write my own empty script for my input.sh bash script but it fails: `empty: Data stream is empty. Keyphrase wasn't found. Exit on timeout.`. Where I tried "waiting", "input" and several other things. – matthias Jul 25 '11 at 14:10
  • Made some progress. I am not sure if I forgot to `chmod +x emptyscript.sh`.. another issue was that it seems I have to `rm -f` the files fifo_in and fifo_out. – matthias Jul 25 '11 at 14:29
  • Thank you everybody. I now have a solution with an `empty` script. Though I'm not quite sure I'm getting all the output of `program` so far.. maybe it needs some more playing around with the script. – matthias Jul 27 '11 at 08:19
2

This sounds like a job for expect! With an expect script, you launch the program from the expect script, which acts as a wrapper that listens for certain patterns in stdout and types stuff into stdin in response. For example, an excerpt that would answer your input.sh script:

#!/usr/bin/expect -f

spawn input.sh
expect ".+input 1"
send "something cool\r"
expect ".+input 2"
send "also cool\r"
expect eof
Leo Accend
  • 321
  • 2
  • 10
  • Thank you! This seems to be a nice solution. Would it still be possible to filter the the output of the program? I'd guess you could just add another pipe to another bash script which does it. The problem is that I am using a linux live CD (systemrescuecd.org) and I don't really want to add an installation procedure. But I am also creating a personalized disk, so this *might* be an option. At least it seems to be a great tool. – matthias Jul 21 '11 at 11:18
  • I think I am not advanced enough. I downloaded the sources for both tcl and expect, unzipped them in /usr/local/src and ran .configure, make and make install. No errors, but I don't get it running. Maybe there is a really simple solution without the aid of additional software (which I'd prefer at this moment). – matthias Jul 21 '11 at 11:54
2

You may also want to consider a client / server model for this kind of task.

See: BASH: Best architecture for reading from two input streams

On a general note, if the stdin of input.shis not a terminal (but rather redirected from a fifo), you have to read explicitly from the controlling terminal device /dev/tty to enable / get user input.

read x < /dev/tty  # in input.sh

./input.sh < fifo 2>&1 | ./inter.sh 2>fifo
Community
  • 1
  • 1
jim
  • 21
  • 1
  • Okay, thanks for the hint. Is it also possible that "program" does not read from stdin but directly from /dev/tty? – matthias Jul 25 '11 at 13:56
2

Here's a small empty snippet scripting a simple telnet session in Bash.

# http://empty.sourceforge.net
cd empty-0.6.18b && man ./empty.1
empty -h 
empty -f -L >(tee empty.log) telnet
empty -l

empty -s <<EOF
display
status
help
quit
EOF

empty -k
cat empty.log
greg
  • 21
  • 1
0

Maybe also play around with the following approach if your automatic user input requirements are not too complex.

#!/bin/bash
# input.sh
echo "input.sh being busy ..."
sleep 10
echo "input.sh: give me input, waiting for input 1"
read x #</dev/tty
echo $x
echo "input.sh: give me input, waiting for input 2"
read x #</dev/tty
echo $x
echo "input.sh continuing ..."


(
echo a
sleep 1
echo b
sleep 1
exec 1>/dev/tty  # redirect anything that would go to stdout/pipe to the screen
ls
#./mylittlebashscript.sh
#./inter.sh
) | ./input.sh   # do not read from /dev/tty in input.sh