1

I want to write a shell script in a more top downish design. I've use to do this with Kornshell scripts. I define various functions that may return multiple set of variables (for example, a getopts function). I can then use these functions in my main program to set the variables I want.

Unfortunately, BASH and Kornshell seem to diverge in the way they handle this instance. Here's a simple script I run in the Kornshell. My function foo returns four values. I'll read in these four values into variables in my main program:

#!/bin/ksh

function foo {
    echo "this:that:the:other"
}

IFS=":"
foo | read one two three four
echo "one = $one"
echo "two = $two"
echo "three = $three"
echo "four = $four"

This produces:

one = this
two = that
three = the
four = other

Works like a charm. Let's try the same program using BASH instead of Kornshell:

#!/bin/bash

function foo {
    echo "this:that:the:other"
}

IFS=":"
foo | read one two three four
echo "one = $one"
echo "two = $two"
echo "three = $three"
echo "four = $four"

This produces:

one = 
two = 
three = 
four = 

The pipe to the read doesn't work at all. Let's try this as a hereis read:

#!/bin/bash

function foo {
    echo "this:that:the:other"
}

IFS=":"
read one two three four<<<$(foo)
echo "one = $one"
echo "two = $two"
echo "three = $three"
echo "four = $four"

I get:

one = this that the other
two =
three =
four =

That allowed $one to be set, but not the other variables. Strangely, the colons were removed from the string. Let's remove the colons from the return value:

#!/bin/bash

function foo {
    echo "this that the other"
}

read  one two three four<<<$(foo)
echo "one = $one"
echo "two = $two"
echo "three = $three"
echo "four = $four"

one = this
two = that
three = the
four = other

That does work. Each variable is read in from function foo.

What am I doing wrong? Why doesn't setting IFS seem to work the way I would think it would in BASH? Or is there a better way to do this?

David W.
  • 98,713
  • 36
  • 205
  • 318

2 Answers2

4

You have to quote:

#!/bin/bash

function foo {
    echo "this:that:the:other"
}

IFS=":"
read one two three four<<<"$(foo)"
                          ^      ^

When executed it returns:

$ ./a
one = this
two = that
three = the
four = other

Regarding this one not working:

#!/bin/bash

...    

IFS=":"
foo | read one two three four
echo "one = $one"

I guess it is because IFS is defined in a different shell than the one having read. Also, to pipe foo to read doesn't seem to be the way to give a string to read in bash.

To do it, open a new shell, as seen on Bash script, read values from stdin pipe:

$ foo | { IFS=":"; read one two three four; echo "one = $one"; echo "two = $two"; echo "three = $three"; echo "four = $four"; }
one = this
two = that
three = the
four = other
Community
  • 1
  • 1
fedorqui 'SO stop harming'
  • 228,878
  • 81
  • 465
  • 523
  • 1
    Yes. The quotes work. Thanks. I guess the pipe doesn't because the `read` and not the `IFS` are in a _subshell_. I hate that with BASH. I have the same issue with `while read` loops too where variables set in the loop are unset outside of the loop because the `while read` is a _subshell_. Works in Ksh, but not in BASH. – David W. Feb 11 '14 at 18:33
  • @DavidW. oh I was updating. See my recommended alternative, by opening the subshell as you say. – fedorqui 'SO stop harming' Feb 11 '14 at 18:37
  • 2
    Keep in mind that there is also a bug in how `read` interacts with `IFS` that may apply here. It's been slated to be fixed in 4.3. – chepner Feb 11 '14 at 18:50
1

Without using read this will also work in both bash and ksh:

IFS=: && set -- `foo`
echo "one = $1"
echo "two = $2"
echo "three = $3"
echo "four = $4"

bts This also works in BASH without creating a sub-shell:

function foo {
    echo "this:that:the:other"
}

IFS=":" read one two three four < <(foo)
echo "one = $one"
echo "two = $two"
echo "three = $three"
echo "four = $four"
anubhava
  • 664,788
  • 59
  • 469
  • 547
  • The second one puts my whole program into a loop. I might be calling multiple functions and setting multiple variables. – David W. Feb 11 '14 at 18:37