How to print text in the terminal as if it's being typed?

This does not work with Wayland; if you're using Ubuntu 17.10 and didn't change to using Xorg at login, this solution isn't for you.

You can use xdotool Install xdotool for that. If the delay between the keystrokes should be consistent, it's as simple as that:

xdotool type --delay 100 something

This types something with a delay of 100 milliseconds between each keystroke.


If the delay between the keystrokes should be random, let's say from 100 to 300 milliseconds, things get a bit more complicated:

$ text="some text"
  for ((i=0;i<${#text};i++));
  do
    if [[ "${text:i:1}" == " " ]];
    then
      echo -n "key space";
    else
      echo -n "key ${text:i:1}";
    fi;
  [[ $i < $((${#text}-1)) ]] && echo -n " sleep 0.$(((RANDOM%3)+1)) ";
  done | xdotool -

This for loop goes through every single letter of the string saved in variable text, printing either key <letter> or key space in the case of a space followed by sleep 0. and a random number between 1 and 3 (xdotool's sleep interprets the number as seconds). The whole output of the loop is then piped to xdotool, which prints the letters with the random delay in between. If you want to change the delay just change the (RANDOM%x)+y part, y being the lower and x-1+y the upper limit – for 0.2 to 0.5 seconds it would be (RANDOM%4)+2.

Note that this approach does not print the text, but rather type it exactly like the user would do, synthesizing single keypresses. In consequence the text gets typed into the currently focused window; if you change the focus part of the text will get typed in the newly focused window, which may or may not be what you want. In either case have a look at the other answers here, all of which are brilliant!


I tried xdotool after reading @dessert's answer but couldn't get it to work for some reason. So I came up with this:

while read line
do
    grep -o . <<<$line | while read a
    do
        sleep 0.1
        echo -n "${a:- }"
    done
    echo
done

Pipe your text into the above code and it will be printed like typed. You can also add randomness by replacing sleep 0.1 with sleep 0.$((RANDOM%3)).

Extended version with fake typos

This version will introduce a fake typo every now and then and correct it:

while read line
do
    # split single characters into lines
    grep -o . <<<$line | while read a
    do
        # short random delay between keystrokes
        sleep 0.$((RANDOM%3))
        # make fake typo every 30th keystroke
        if [[ $((RANDOM%30)) == 1 ]]
        then
            # print random character between a-z
            printf "\\$(printf %o "$((RANDOM%26+97))")"
            # wait a bit and delete it again
            sleep 0.5; echo -ne '\b'; sleep 0.2
        fi
        # output a space, or $a if it is not null
        echo -n "${a:- }"
    done
    echo
done

You mention a consistent delay between characters, but if you really want it to look like its being typed, the timing won't be perfectly consistent. To achieve this you can record your own typing with the script command and play it back with scriptreplay:

$ script -t -c "sed d" script.out 2> script.timing
Script started, file is script.out
Wake up ...
Wake up ...
Wake up Neo ...
Script done, file is script.out
$ 
$ scriptreplay script.timing script.out
Wake up ...
Wake up ...
Wake up Neo ...

$ 

Recording is stopped by hitting CTRL-D.

Passing the -t parameter to script instructs it also generate timing information, which I have redirected to the script.timing file. I have passed sed d as a command to script as this is simply a way to absorb input (and this record the keystrokes) with no side-effects.

If you want to do all the tput/reset stuff too, you might want to do a script recording for each of your lines, and play them back, interleaved with the tput/reset commands.