views:

799

answers:

4

I want to make a script that starts a program and then sends it key input. In psuedo-script:

#!/bin/bash
./program << (PRESS CONTROL-Z)

The program is running so if there were additional commands in the script they will not be reached unless say control-z terminates the program.

Is this possible? From what I've found I thought it might require key codes but I could be wrong.

A: 

You might be looking for expect (from http://expect.nist.gov/). This deals with the complexities of pseudo-ttys that make it appear to the program that the input from the script (in this scenario, the expect program) is coming from a terminal.

Alternatively, you might be able to use echo or cat and pipe the output of that into the program - it depends on the program.

Jonathan Leffler
The thing with piping into the program is I need someway to simulate the control key, this isn't just text commands.
Sandy Vanderbleek
@Sandy Vanderbleek: Not in general, no. You *can* echo the control characters to the command, but generally these are not treated the same way as pressing e.g. Ctrl-Z in the shell (in which case it is the shell, and not the command, which gets the input).
Arkku
@Sandy: If the program processes characters, then control characters present no particular problem. If your program is detecting key presses and releases, then you have a bigger problem. For sure, neither echo nor cat will handle key presses. I suspect that expect doesn't either - but that would require some checking.
Jonathan Leffler
I think expect will work since I looked into it, thanks. I still have to figure out how to use expect.
Sandy Vanderbleek
@Sandy: Amongst other places: http://expect.nist.gov/FAQ.html#q54
Jonathan Leffler
@Arkku: note that one of the reasons for using pseudo-ttys and expect is so that you *do* get the effect of ^Z when you type control-Z.
Jonathan Leffler
A: 

If you just want the program to start in the background, just do

#!/bin/bash
./program&
Jason Coco
A: 

If your intent is to background the program, use:

./program &    # The & sends the command to the background
echo commands here are executed while program is in the background
…
wait           # Wait for the completion of background commands
echo commands here are executed after background program has completed

Edit: If your intent is to stop the program (as ctrl-Z often does in *nix shells), you can send it the STOP signal:

kill -STOP pid

To resume the execution, send it the CONT signal:

kill -CONT pid

In each of these examples pid is the process id of the program. If you launch it in a script, it's easy to get with the variable $!, e.g.

./prog &
echo prog started in the background
pid_of_prog=$!
kill -STOP $pid_of_prog
echo prog stopped
kill -CONT $pid_of_prog
echo prog continues
wait
echo prog finished

Edit 2: If your program is one that exits when it receives a ctrl-Z character, then remember that the control characters have the numerical value of the position letter in the alphabet (i.e. Ctrl-A is 1, Ctrl-B is 2, etc.). To send this character to a program you can:

echo -e "\032" | ./prog

(032 is 26, i.e. ^Z, in octal. Of course you can produce the same character by any means, perhaps adding it to the end of other input like ( cat inputfile ; echo -e "\032" ) | ./prog.

But this may not necessarily work; the program must be designed to recognise this character from the input (which it probably won't); usually the shell catches it. Then again, most programs reading input from stdin just exit when the input ends, so redirecting any finite input (even </dev/null) should cause it to terminate.

And, finally, if the intent was to stop the execution of the program when some other event (detected elsewhere in the script) has occurred, you can just kill it…

Arkku
This sounds good, but I'm not sure how I would get the effect of pressing control-z with the process in the background.
Sandy Vanderbleek
@Sandy Vanderbleek: I'm still not quite certain what the ctrl-z you're after is supposed to do, but I edited the answer with some alternatives.
Arkku
A: 

This I think is probably a better solution than "expect" since it can be executed in native bash script, I'll be interested to see what you think.

Use

`printf "character code here"` 

note the backticks

So for instance I have written a script that controls a remote gnu screen session, the following line opens window 2 and issues the ctrl-c key combo

ssh -t user@$host screen -p 2 -X stuff `printf "\003"`
  • The -t option simulates terminal input on the remote machine
  • -p allows us to specify the name or number of the window we are connecting to within the screen session.
  • \003 is the bash format of character code 0x03

See here for a complete reference of codes.

To find the code of some key input you can use

printf "%#x\n" "'X"
0x58
  • Were X is the key you want to find the code of
  • To find codes of non literals you can use ctrl-v (makes bash append the next key to the command line rather than intepret it) and then type the key combo, so if I wanted to find the key code for ctrl-c I would delete the X press ctrl-v and then press ctrl-c.

One last thing the ascii code reference mentioned above lists 0x13 as the carriage return, but in the screen manual they list 0x15 as the enter key code, does anyone know why? Ive tested in a local screen and when I press enter 0x13 is produced, but when sending commands via ssh to a remote screen 0x13 doesn't work but 0x15 does.

Hope that helps

Piers

PiersyP