Reputation: 2375
I am trying to read a keystroke input from the keyboard and assign it to a variable key
. I am using read
as follows:
read -sn1 key && echo "${#key}" "\"$key\"" "${key:?}"
This reads a single character (aka keystroke) from the keyboard and sets key
to that character and echos info about key
. If I type a readable character (d
), it will show, for example:
1 "d" d
But if I type a tab or space, I get (from the last part of the echo
statement):
bash: key: parameter null or not set
However, if I use the default REPLY
and hit the space bar, it works as expected when I hit the space bar:
$ read -sn1 && echo "${#REPLY}" "\"$REPLY\"" "${REPLY:?}"
1 " "
Also, if I explicitly specify REPLY
as the name of the variable to use, explicitly, it does not work as the last example showed, instead, it fails as when I used key
.
$ read -sn1 REPLY && echo "${#REPLY}" "\"$REPLY\""
0 ""
What's going on? It seems like specifying a name
to read
to store the results to cause it to lose whitespace-only input. (I verified this by removing -n
and entering longer whitespace-only input).
Upvotes: 1
Views: 175
Reputation: 531165
read
performs word-splitting on the line it reads in order to set the variables provided as its arguments. As part of word-splitting, any leading or trailing whitespace is discarded; other whitespace is retained if splitting isn't required to produce the requested number of fields. For example,
$ read a b <<< " foo bar baz "
$ echo "=$a="
=foo=
$ echo "=$b="
=bar baz=
Because only two fields are requested, the whitespace between bar
and baz
is left alone.
Wordsplitting occurs even if only one name is used.
$ read a <<< " foo bar "
$ echo "=$a="
=foo bar=
There are two ways to disable word-splitting:
IFS
. This retains all leading/trailing whitespace and assigns the entire line to the first name given as an argument.bash
extension uses the name REPLY
if no name arguments are provided to read
; word-splitting is not performed before assigning the input to REPLY
.Upvotes: 2
Reputation: 123470
Here's help read
:
The line is split into fields as with word splitting, and the first word is assigned to the first NAME, the second word to the second NAME, and so on, with any leftover words assigned to the last NAME. Only the characters found in $IFS are recognized as word delimiters.
If no NAMEs are supplied, the line read is stored in the REPLY variable.
You'll notice that this means that read
is not the same as read REPLY
.
When you specify a name argument, word splitting will occur (even if it's just one). If you don't specify a name, the line is simply stored in REPLY
as-is, i.e. without any word splitting. This is how the single space survives.
Upvotes: 4