0

This question already has an answer here:

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.

marked as duplicate by muru, Romeo Ninov, EightBitTony, G-Man, ilkkachu Dec 19 '17 at 8:29

This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.

  • 2
    Any values you're seeing are not from the read. – muru Dec 19 '17 at 6:55
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.

  • 1
    Worth mentioning that IFS can be declared just for read. – PesaThe Dec 19 '17 at 12:33
  • 1
    @PesaThe Excellent suggestion! Answer updated with local variable assignment. – John1024 Dec 19 '17 at 18:40

Not the answer you're looking for? Browse other questions tagged or ask your own question.