I want to do the following in bash: I have a textfile, and want to call a script that reads the file, waits for keystrokes from me and each time a correct button is pressed, it prints exactly one word (the next word) from the textfile.

To elaborate: Let's just say the textfile looks like the following

This is my
text file

and I am looking for keyboard buttons of the group [[:print:]]. So I call my script like ./script.sh textfile, then I press "A" and the Thisappears, then I press the Space button, still only the This, then I type "O" and the is appears, I press maybe "M" a few more times, until all of the text above is printed, and I'm done.

What I already have:

I already know how to wait for a single keypress and then do something if it works:

while true; do
  read -rsn1 input
    if [[ "$input" =~ "[[:print]]" ]]; then
     # do stuff on keypress

I also know how to read a file word by word: Read File word by word (I used answer of user Lambert)  The combination of the two does not seem to work how I want it though. 

If anyone has any idea on how to do this, I'd greatly appreciate it. Also, please remark if I did formulate anything unclear/wrong or if I asked in the wrong place/manner.

Edit for clarification The Textfile may contain an arbitrary number of lines. Each keypress should print words exactly like it stands in the Textfile, i.e. it conserves spaces and newlines (think of the script I want to achieve as a delayed cat that prints not the whole file at once, but only Word by Word on keystroke)

  • Is that just one line in textfile, or can there be more than one?
    – RudiC
    Oct 11, 2018 at 8:01
  • in regards to the keys you're pressing, I see no connection between them. Can you clarify if you're expecting any alpha-numeric keystroke to print the next word? Oct 11, 2018 at 8:01
  • @RudiC Yes, Textfile may contain an arbitrary number of lines.
    – Pharguin
    Oct 11, 2018 at 8:08
  • @RobotJohnny Sorry if I did not make it clear. I am expecting any alpha-numeric keystroke, i.e. a-z A-Z 0-9.
    – Pharguin
    Oct 11, 2018 at 8:09

1 Answer 1


You're not too far off for a one line file. Try arrays and get rid of your syntax errors:

read -a TMPARR < file
while read -n1 CH && [[ $CNT -lt ${#TMPARR[@]} ]]; do [[ "$CH" =~ [[:print:]] ]] && echo ${TMPARR[((CNT++))]}; done

For a multiline file, try

while read -a TMPARR <&3
   do   CNT=0
        [[ $CNT -lt ${#TMPARR[@]} ]] && read -sn1 CH
        while read -sn1 CH && [[ $CNT -lt ${#TMPARR[@]} ]]
          do [[ "$CH" =~ [[:print:]] ]] && echo ${TMPARR[((CNT++))]}
   done  3< file

You have to split the input file descriptors for reading the text lines sequentially and reading from the terminal in parallel.

  • How could I modify this so this works for multiple lines? I added a short clarification to my question on how I want the output to look, too.
    – Pharguin
    Oct 11, 2018 at 8:31
  • Thanks for your Input so far. This almost does the trick. It still prints every word seperate on a new line. If I use echo -n "${TMPARR[((CNT++))]} " I get the text separated by spaces. Still, all newlines from the original file are omitted (I am guessing because of how the Array gets created?). I want to keep the formatting exactly like in the original file though, so with all linebreaks, spaces, identations etc intact, if possible.
    – Pharguin
    Oct 11, 2018 at 9:58
  • Would adding an echo between the two dones help?
    – RudiC
    Oct 11, 2018 at 10:26
  • This does the trick! Thanks and accepted.
    – Pharguin
    Oct 11, 2018 at 10:53

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .