Categories
Shell Scripting

Bash programers should read more

One of the most misunderstood commands in bash is read. I consider this a shame because it’s one of the most useful. I was reminded of this recently when someone asked me to look over a shell scripting manual they had written. When I came to the read command there was less than a page dedicated to it. This brevity gave very little understanding of how the command worked and no example of how to really use it. The classic use everyone is familiarwith is to pull in user input. While this is useful it hardly scratches the surface of the command itself.

Classic Example:

$ read x
this is a test
$ echo $x
this is a test

This is where everyone’s knowledge seems to end. I ask you to consider this command again though. What else does it do? What is it really doing? How can you use that to your advantage?

Did you know read takes multiple variables? There are two separators you should be aware of, an internal separator which is a space, and the external separator which is a carriage return (the enter button). Read works like this:

Stop and wait for input
Receive text to a separator (space or enter)
Set variable to text
If inside separator, go to next variable. If no more variables are available, go to last variable
if outside variable, exit

Knowing this we can add a little more to our read command….

$ read x y z
this is a test
$ echo $x
this
$ echo $y
is
$ echo $z
a test

Oh.. no we’re getting somewhere. We can now set variables by field without having do so later in the script. But can we change the field separator? YES!!!

$ IFS="1" read x y z
this1is1a1test
$ echo $x
this
$ echo $y
is
$ echo $z
a1test

Now we’re getting somewhere. That is pretty cool, but it’s just for user input right? Nope! this is where the read command starts to get fun. Knowing all this, you can now use the read command to set variables!

FOO="this|is|a test"
IFS="|" read x y z <<< $FOO
$ echo $x
this
$ echo $y
is
$ echo $z
a test

Hopefully you are coming up with lots of fun ways to use this new knowledge….. but we are not done yet! Let’s consider a data file separated by pipes named ‘flowers’.

iris|purple
rose|red
dasie|white
dogwood|white

We can now pull out each variable individually and work with it inside a loop.

while IFS="|" read FLOWER COLOR _ ; do
  echo "The $FLOWER is $COLOR"
done <<< flowers

Try this for yourself! I’ll be posting a few other variations of this loop later, but this is fun to play around with. One of the advantages in using this method is the loop passes variables. Many methods of using while loops you’ll find you cannot set variables within it (because of the subshell). In this format that isn’t the case. The subshell is passed to the read command rather than the interior of the loop. (Yeah, I know, that’s a little confusing just remember to use this format if you are setting variables inside your loop)

You may be wondering what the underscore is for at the end of the read command. Remember from earlier the last variable you set within your read command will take all input after it. By putting an underscore as your last variable, the rest of the data will just be dropped keeping you from having extra characters. Doing this is a good (and more secure) habit to be in.

Happy scripting!

Leave a Reply

Your email address will not be published. Required fields are marked *