Sending simulated keystrokes in Bash

76,359

Solution 1

To feed text into a program's stdin, use pipes and/or redirection:

echo 1 | myprogram

(echo "First line"
 echo "Second line") | myprogram

myprogram <<EOF
First line
Second line
EOF

In case of interactive CLI programs (not full-terminal ones), it is possible to use named pipes or coprocesses as a sort of poor-man's expect (which you ruled out due to being Tcl):

mkfifo in out
myprogram <in >out &
echo "First line" >in
read -r reply <out

mkfifo in out
myprogram <in >out &
exec {infd}>in {outfd}<out
echo "First line" >&$infd
read -r reply <&$outfd

coproc foo { myprogram; }
echo "First line" >&${foo[1]}
read -r reply <&${foo[0]}

(Be careful when reading from the output pipe; e.g. head -1 <out won't just read one line – it'll buffer one full 4k block, print one line, discard the rest.)

Solution 2

You're looking for xdotool.

xdotool's equivalent of your example commands are:

xdotool key 1 Return
xdotool keydown Alt key a keyup Alt

Solution 3

A favourite of mine is "tmux".

Warning - some level of spoon-feeding here, though the question is old enough that the original author would no doubt have completed what they originally intended.

You can easily launch tmux in the background, launching an application. Tmux provides an API to send key strokes to the application, as well as connect the application to the terminal if you want to interact with it.

Example:

$ tmux new-session -d -s Super
$ tmux send-keys -t Super: "uuid" "Enter"
$ tmux capture-pane -t Super: -S - -E - -p | cat -n

$ uuid

fe253d00-3432-11eb-9984-cb225a8f7d48

$ tmux kill-session -t Super:

new-session -d -s Super Create a new session called Super in the background (-d). Note -s to new-session names the session. I havent named an application to run, so a shell is launched.

send-keys -t Super: "command" "Enter" Send the keystrokes. Tmux understands many keywords like Enter, PgUp, Escape, etc, otherwise sending UTF and raw codes via send-keys -t Super: $'command\n' also works. Note the -t refers to a target which includes [session]:[window id]:[pane #]. Since I have only the default window and pane, I leave them blank and refer only to the session. If I know there were no other sessions running, I could leave out -t entirely.

capture-pane -t Super: -S [start] -E [end] -p Copies the contents of the window. By default, panes are captures to internal buffers you can save, or paste to other windows. the -p causes the contents to be piped to the screen. Note the captured data can be much longer than a screenfull.

The best part is, if you have left the application or session running, tmux attach -t Super: will drop you into the running session so you can interact with the application.

Many people use tmux to launch long running interactive programs as a background service they can attach to later, or as part of an automated test solution.

Share:
76,359

Related videos on Youtube

Ishan
Author by

Ishan

I am a 7th grade student who likes computer programming a lot. I am frustated by the closed-indedness about programming at our school. One custom program here or there, and you lose marks. I am a QBASIC guru. I have some experience of visual basic. currently I am learning C++. It is my dream to be a programmer.

Updated on September 18, 2022

Comments

  • Ishan
    Ishan almost 2 years

    I've recently been trying to write a script that can be used to automate my c++ program in bash. If you know AutoIt, I can simply show you an example of what I am trying to do:

    send("1{enter}")
    

    or

    send("!a")
    

    OK For those who do not speak AutoIt:

    The first example sends a simulated "1" keystroke followed by an enter(CR)

    The second example sends alt-a

    I'm specifically trying to do this in bash. No other scripting language will do

    Also, I would not prefer a spoonfeed. Please specify how to write it. No writing the script for me is allowed.

    • user1686
      user1686 about 11 years
      Are you automating a command-line, ncurses, or graphical program?
    • Ishan
      Ishan about 11 years
      I'm automating a command line for now. It is supposed to feed input into cin's(console inputs) automatically
  • user1686
    user1686 about 11 years
    @Ishan: It's practically impossible to do such things with pure bash code. Bash cannot use X11 directly, and it cannot use any existing X11 library either. You would have to connect to the X11 socket directly (bash only does TCP, not Unix sockets), parse the X11 protocol by hand (parsing binary data in bash is destined to fail) and craft the apropriate responses. bash is a shell, it is designed to work by chaining external tools.
  • Ishan
    Ishan about 11 years
    Both of the answers are equally good. But, this is what I weas more looking for.
  • Chris Stryczynski
    Chris Stryczynski over 6 years
    What is meant by CLI program / full terminal?
  • Trevin Avery
    Trevin Avery about 6 years
    CLI stands for Command Line Interface. A CLI program is a simple program that runs on the command line and generally uses stdin and stdout as it performs some task and then finishes execution and returns to the command line prompt. grep and curl are good examples of this. A full terminal program is something that takes control of the entire window, like vim and screen.
  • Wayne Walker
    Wayne Walker over 3 years
    Didn't answer the OP's question, but I was looking for what the OP was, and this answer changed my mind! Thanks @Dave
  • Deoxal
    Deoxal almost 3 years
    This looks cool, but I don't understand what the man page is saying about the window stack and how I can send the keyboard input to the proper Window. In my case I want to send it to a game window in Wine which has a virtual desktop window underneath it when in fullscreen mode.
  • Tim Mottram
    Tim Mottram over 2 years
    I know I'm really really late to this, but if a program is 'full terminal' - is there a way to get data out of it? I'd love to pipe the program to grep and parse it's contents. Any ideas?
  • user1686
    user1686 over 2 years
    @TimMottram: Terminal emulators also come as libraries (e.g. vte, libvterm, etc). Someone could write a tool that creates a pty and runs the program in it (like 'expect' does) but feeds its output to a library like libvterm, which will interpret all the drawing/cursor control sequences and allow the tool to get straightforward "text screenshots" of the program and extract data out of them.