I have a simple echo
print out that I've added to my .bashrc
:
echo "$(tput setaf 2)Wake up....."
sleep 2s
reset
sleep 2s
echo "$(tput setaf 2)Wake up....."
sleep 2s
reset
echo "$(tput setaf 2)Wake up neo....."
sleep 2s
echo "$(tput setaf 2)The Matrix has you......"
sleep 2s
reset
echo "$(tput setaf 2)Follow the white rabbit......"
sleep 2s
reset
cmatrix
This prints a message to terminal, but I want it look as though it's being typed, with a consistent delay between characters.
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
for that. If the delay between the keystrokes should be consistent, it's as simple as that:This types
something
with a delay of100
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:
This
for
loop goes through every single letter of the string saved in variabletext
, printing eitherkey <letter>
orkey space
in the case of a space followed bysleep 0.
and a random number between 1 and 3 (xdotool
'ssleep
interprets the number as seconds). The whole output of the loop is then piped toxdotool
, 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 andx-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:
Pipe your text into the above code and it will be printed like typed. You can also add randomness by replacing
sleep 0.1
withsleep 0.$((RANDOM%3))
.Extended version with fake typos
This version will introduce a fake typo every now and then and correct it:
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 withscriptreplay
:Recording is stopped by hitting CTRL-D.
Passing the
-t
parameter toscript
instructs it also generate timing information, which I have redirected to thescript.timing
file. I have passedsed d
as a command toscript
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 ascript
recording for each of your lines, and play them back, interleaved with thetput
/reset
commands.Another possibility is using Demo Magic, or, to be more precise just the print function of this script collection, which basically amounts to
Under the hood, this uses pv, which of course you can also use to directly get the desired effect, the basic form looks as follows:
In line with my nickname I can offer another solution:
Looks weird, doesn't it?
-MTime::HiRes=usleep
imports the functionusleep
(microsecond sleep) from theTime::HiRes
module because the usualsleep
accepts only integer seconds.-F''
splits the given input into characters (the delimiter being empty''
) and puts the characters in the array@F
.BEGIN {$|=1}
disables output buffering so each character is immediatly printed.for (@F) { print; usleep(100_000+rand(200_000)) }
just iterates over the characters1_000
(==1000
) or even1_0_00
if we consider that easier to read.rand()
returns a random number between 0 and the given argument, so together this sleeps between 100,000 and 299,999 microseconds (0.1-0.3 seconds).I'm surprised nobody's mentioned this yet, but you can accomplish this with stock tools and a loop:
It just loops over the input character by character and prints them out with a delay after each. The only tricky bit is that you have to set your IFS to an empty string so bash doesn't try to split away your spaces.
This solution is dead-simple, so adding variable delays between characters, typos, whatever is super easy.
EDIT (thanks, @dessert): If you want a slightly more natural interface, you could instead do
This would allow you to call the function as
typeit foo bar
rather thantypeit 'foo bar'
. Be aware that without quotes, the arguments are subject to bash's word splitting, so for exampletypeit foo<space><space>bar
will printfoo<space>bar
. To preserve whitespace, use quotes.Another tool that might work, which does not depend on x11 or whatever, is asciicinema. It records everything you do in your terminal and lets you replay that as if it were a screen capture, only then it's purely ascii based! You might have to temporarily disable your prompt however for it to be purely visually clean. As other have pointed out, adding a consistent delay will not look natural, and typing it yourself might be one of the most natural looks you can achieve.
After having recorded the text, you can do something like:
First, "look as though it's being typed, with a consistent delay between characters..." is a little contradictory, as others have pointed out. Something being typed doesn't have a consistent delay. When you see something produced with an inconsistent delay, you'll get chills. "What's taken over my computer!!!??!?"
Anyway...
I have to make a shout out to
expect
, which should be available on most Linux distributions. Old School, I know, but- assuming it's installed- it could hardly be simpler:From the man page:
See https://www.tcl.tk/man/expect5.31/expect.1.html