Share your knowledge at the LQ Wiki.
Go Back > Linux Answers > Programming
User Name


By A.Thyssen at 2011-09-30 03:33
This comes out of a discussion...

Bash script to accept password and replace characters with * as they are typed

Reading ANY character in BASH...
   IFS= read -r -s -d '' -n 1 char
The "$char" variable is only valid if a character was actually read, and that only happens if its status is true (0).

If its exit status is not true then either EOF has been reached (exit status = 1) or some error occurred (exit status > 128). That latter can happen for example if the shell script received a broken pipe, but the SIGPIPE is being ignored.

There is however a special condition... If the read returned true, but the "$char" variable is empty, then the read command actually read a NULL character. Bash can not handle NULL characters in its variables, so it sees an empty variable.

This is the important special case that needs to be handled so as to allow BASH to read any character from its input stream.

Here is an example of using it...
  printf 'a\tb\rc\nd\0e' |
    while IFS= read -r -s -d '' -n 1 char
      if [[ "$char" == '' ]]; then echo -n "-NULL-"
      elif [[ "$char" == $'\r' ]]; then echo -n "-RETURN-"
      elif [[ "$char" == $'\n' ]]; then echo -n "-NEWLINE-"
      elif [[ "$char" == $'\t' ]]; then echo -n "-TAB-"
      else echo -n "$char"
The result output is... a-TAB-b-RETURN-c-NEWLINE-d-NULL-e perfect!

Note I used the built-in "printf" command so I can actually output a NULL. "echo" can not be used for printing NULL characters. You can check the output contains NULL's using
   printf 'a\tb\rc\nd\0e' |  od -c
Both the IFS= and the " -d '' " option in the "read" command is important, otherwise read will delimit the input based on white-space (no IFS=) or NEWLINES (no -d).

If the -d is not included then NEWLINE will also return an empty string (as a delimiter) in which case the result is a-TAB-b-RETURN-c-NULL-d-NULL-e

This may be desirable in some cases.

Timeout Reads...

The read can be made more complicated by also allowing it to timeout
   IFS= read -r -s -d '' -n 1 -t 1 char
You still only get a true exit status if a character is read. but you may also get a exit status of 142 on linux machines if the read timed out.

Poll reads (warning)...

If you use a zero timeout " -t 0 " so as to 'poll' to see if there is any input waiting, then you will not get a timeout exit status. Instead (at least on my machine) I get a exit status of 1 the same as for an EOF condition. -- This I regard as a BUG in BASH.

I have not been able to find a way to use read to 'poll' for input and differentiate between no input and a EOF condition, using pure BASH. :-(

Though one method I have found is to use a small perl script to make a IO library 'select()' system call to see if input is available before doing the "read". But I consider that cheating.

Anthony Thyssen <>


All times are GMT -5. The time now is 06:43 AM.

Main Menu
Write for LQ is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration