0

From the bash man page for the read command:

One line is read from the standard input, or from the file descriptor fd supplied as an argument to the -u option, split into words as described above under Word Splitting, and the first word is assigned to the first name,...

Now I tried out the following:

IFS=,
echo ' a b,c d'|read -n 4 x y
echo ".$x. .$y."

I expected the output to be

. a b. .c d.

becaus due to the change, word splitting should occur at the comma instead of the space, but the actual output was

.a. ..

This puzzles me. The .a. looks like word splitting is still done at spaces, but then at least, y should be set to b, not being empty.

I can't help but feeling that I misunderstand the explanations in the man-page about the read command.

BTW, I'm using bash 4.4.12.

user1934428
  • 707
  • 5
  • 15

1 Answers1

4

It works just fine:

$ IFS=,; echo ' a b,c d' | { read x y; declare -p x y;}
declare -- x=" a b"
declare -- y="c d"

Notes

  1. Because it is in a pipeline, the read statement is in a subshell. The variables x and y are limited in scope to that subshell. In the above, we added curly braces so that the declare statement was in the same subshell as the read statement. That way, the declare output shows the values of x and y that were read.

    If we remove the curly braces, then the declare statement is no longer in the same subshell and the values of x and y are not preserved. Observe:

    $ x=hot; y=cold; IFS=,; echo ' a b,c d' | read -n 4 x y; declare -p x y
    declare -- x="hot"
    declare -- y="cold"
    
  2. To avoid the subshell limit, we can use a here-string:

    $ IFS=,; read x y <<<' a b,c d'; declare -p x y
    declare -- x=" a b"
    declare -- y="c d"
    

    With a here-string, the read statement is in the main shell and the values of x and y are not lost.

  3. -n 4 limits read to 4 characters. That probably is not what you wanted. Observe:

    $ IFS=,; echo ' a b,c d' | { read -n 4 x y; declare -p x y;}
    declare -- x=" a b"
    declare -- y=""
    

    Here, x takes up all 4 characters (blanks do count as characters), there are no characters read for y.

  4. As PesaThe, it is also possible to assign shell variables locally just for the execution of one command. Because changes to IFS might cause unwanted side-effects in subsequent commands, that is a good idea here. Thus:

    $ IFS=, read x y <<<' a b,c d'; declare -p x y
    declare -- x=" a b"
    declare -- y="c d"
    

    After the above command is run, IFS is returned to its previous value.

John1024
  • 74,655