0

This command:

read -d 'z' a < <(printf 'a\n\n\n'); printf "$a"

outputs:

a

bash's read removes excess trailing newlines which is expected.

and by changing the IFS to null character:

IFS= read -d 'z' a < <(printf 'a\n\n\n'); printf "$a"

it outputs:

a 
(blank line)
(blank line)

read no longer removes the excess trailing newlines since IFS no longer includes newline character ...

but now if we do the same but with m instead of newlines:

IFS=m read -d 'z' a < <(printf 'ammm'); printf "$a"

one would think the output would be:

a

but the actual output is:

ammm

i.e. now read doesn't remove the excess trailing IFS characters (in this case m character).

why?

2

Field splitting specifically ignores leading and trailing IFS whitespace. From the GNU Bash manual, 3.5.7 Word Splitting:

If IFS is unset, or its value is exactly <space><tab><newline>, the default, then sequences of <space>, <tab>, and <newline> at the beginning and end of the results of the previous expansions are ignored, and any sequence of IFS characters not at the beginning or end serves to delimit words. If IFS has a value other than the default, then sequences of the whitespace characters space, tab, and newline are ignored at the beginning and end of the word, as long as the whitespace character is in the value of IFS (an IFS whitespace character).

The courtesy isn't extended to non-whitespace characters. You can check this using other instances of field splitting:

bash-5.0$ printf "|%s|\n" $(printf '\n\na\nb\n\n')
|a|
|b|
bash-5.0$ IFS=' '; printf "|%s|\n" $(printf '  a b  ')
|a|
|b|
bash-5.0$ IFS=z; printf "|%s|\n" $(printf 'zzazbzz')
||
||
|a|
|b|
||
| improve this answer | |
1

by default read strips leading/training white space and newlines. If you add IFS then the default value is there so read won't strip them.

In your example

IFS=m read -d 'z' a < <(printf 'ammm'); printf "$a"

You gave IFS a value so now you have 2 fields/column but you only gave one variable to read which is a, If you gave another variable which will hold the second feld

IFS=m read -d 'z' a b < <(printf 'ammm'); printf '%s %s' "$b" "$a"

mmm a

I'm not good on the details so someone can explain more but that's how I understood it.

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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