Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

bash: reading text from a string one character at a time, with whitespace

Tags:

bash

char

sleep

ifs

I'm bored, and decided to write a script for a text-based adventure of mine using bash. Basically, it's supposed to animate a typewriter in certain cases for dramatic storytelling. I can do this manually in a file like so:

sleep 0.1 
echo -n "h"
sleep 0.1 
echo -n "e"
sleep 0.1 
echo -n "l"
sleep 0.1 
echo -n "l"
sleep 0.1 
echo -n "o"

As you can imagine, it's dreadfully tedious. Instead, I want to pull characters from a string (or file) one character at a time, and apply the sleep command to each character.

So far, I have the following, that reads from a file. IFS= allows the spaces to retain, but not any other type of whitespace (such as newline).

IFS=
while read -n1 achar
do
   echo $achar
done < aFile

Is there a way I can use this to get all whitespace? As a bonus question, can you tell me how to apply this to a user-defined script, so I don't have to read from a separate file? So, for example, lets say I have a string called "hello", and I can simply pass it to my function to animate as a typewriter whenever I run my file in the bash terminal.

Any help would be appreciated. Thanks!

like image 249
derp Avatar asked May 05 '12 04:05

derp


People also ask

Does Bash ignore whitespace?

Bash uses whitespace to determine where words begin and end. The first word is the command name and additional words become arguments to that command.

Why does my shell script choke on whitespace or other special characters?

Always use double quotes around variable substitutions and command substitutions: "$foo" , "$(foo)" If you use $foo unquoted, your script will choke on input or parameters (or command output, with $(foo) ) containing whitespace or \[*? . There, you can stop reading.

What does $@ do in bash script?

bash [filename] runs the commands saved in a file. $@ refers to all of a shell script's command-line arguments. $1 , $2 , etc., refer to the first command-line argument, the second command-line argument, etc. Place variables in quotes if the values might have spaces in them.

What does #$ mean in Bash?

#$ does "nothing", as # is starting comment and everything behind it on the same line is ignored (with the notable exception of the "shebang"). $# prints the number of arguments passed to a shell script (like $* prints all arguments). Follow this answer to receive notifications.


2 Answers

How about

#!/bin/bash

function typewriter
{
    text="$1"
    delay="$2"

    for i in $(seq 0 $(expr length "${text}")) ; do
        echo -n "${text:$i:1}"
        sleep ${delay}
    done
}


typewriter "Typewriters are cool." .1
echo # <-- Just for a newline
like image 125
jedwards Avatar answered Oct 19 '22 06:10

jedwards


To answer the original question, you need to use an empty delimiter as well:

#!/bin/bash
getc() {
  IFS= read -r -n1 -d '' "$@"
}

typewriter() {
  while getc ch; do
    sleep 0.1; echo "$ch"
  done
}

Basically, read will stop at newlines (the default delimiter) even if it hasn't consumed enough characters yet. The -r flag also tells it to leave backslashes alone.

Full explanation here: http://jayferd.us/posts/2011-01-12-bash-adventures-read-a-single-character-even-if-its-a-newline

like image 20
Jeanine Adkisson Avatar answered Oct 19 '22 04:10

Jeanine Adkisson