IFS=$'?\n'for line in $(cat ./newfiletoread)do printf ${line}\ndoneThe file contents are as below:Hello there!How are you doing?How is life?Mine is as boring as a winter morning!The code above splits the contents of the file when it comes across a '?' or '!' or '/n' which is nice. But, during the expansion the shell removes these characters from the file. The below is the output that I get.Hello there How are you doingHow is lifeMine is as boring as a winter morningI understand that it is how shell works by substituting these IFS values with spaces before the command executes. Is there a way to preserve these delimiter characters during the splitting? I would like to get my output like this one below:Hello there! How are you doing?How is life?Mine is as boring as a winter morning!
Why is the IFS value removed from the file while splitting?
shell script;command substitution;bash expansion
First, don't read the lines of a file with forI read this somewhere about splitting strings: use split when you know what to throw away; use a regular expression when you know what you want to keep. Or something like that.The problem with using shell word splitting using $IFS is that any char in that variable is used to split, and you can't know which one.With bash, you can write:line='Hello there! How are you doing? How is life? Mine is as boring as a winter morning!'line=${line//\?/$'?\n'}line=${line//\!/$'!\n'}echo $lineHello there! How are you doing? How is life? Mine is as boring as a winter morning!Note the leading spaces. That can be worked around with a more complicated pattern: line=${line//\?*([[:blank:]])/$'?\n'}I would use sed instead:line='Hello there! How are you doing? How is life? Mine is as boring as a winter morning!'new=$( sed 's/[?!][[:blank:]]*/&\n/g' <<<$line )echo $newHello there! How are you doing? How is life? Mine is as boring as a winter morning!awk has a split() function that does let you capture the separators, but using it is pretty verbose:echo $line | awk '{    n = split($0, words, /[!?][[:blank:]]*/, seps)    for (i = 1; i < n; i++)         print words[i] seps[i]    print words[n]}'