为什么在分割时 IFS 值会从文件中删除?

为什么在分割时 IFS 值会从文件中删除?
IFS=$'?\n'
for line in $(cat "./newfiletoread")
do printf "${line}\n"
done

文件内容如下: 你好!你好吗?生活怎么样?我的生活就像冬天的早晨一样无聊!

上面的代码在遇到“?”时分割文件的内容或者 '!'或者'/n',这很好。但是,在扩展过程中,shell 会从文件中删除这些字符。以下是我得到的输出。

Hello there 
How are you doing
How is life
Mine is as boring as a winter morning

我知道 shell 的工作原理是在命令执行之前用空格替换这些 IFS 值。有没有办法在分割过程中保留这些分隔符?我想得到像下面这样的输出:

Hello there! 
How are you doing?
How is life?
Mine is as boring as a winter morning!

答案1

第一的,不要读取文件的行for

我在某处读到过关于分割字符串的内容:split当你知道要扔掉什么时使用;当您知道要保留什么时,请使用正则表达式。或类似的东西。

使用 shell 分词的问题$IFS是,该变量中的任何字符都用于拆分,而您无法知道是哪一个。

使用 bash,您可以编写:

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 "$line"
Hello there"!
 How are you doing"?
 How is life"?
 Mine is as boring as a winter morning"!

注意前导空格。这可以通过更复杂的模式来解决:line=${line//\?*([[:blank:]])/$'"?\n'}

我会用sed

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 "$new"
Hello there! 
How are you doing? 
How is life? 
Mine is as boring as a winter morning!

有一个split()函数可以让你捕获分隔符,但使用它非常冗长:

echo "$line" | awk '{
    n = split($0, words, /[!?][[:blank:]]*/, seps)
    for (i = 1; i < n; i++) 
        print words[i] seps[i]
    print words[n]}
'

相关内容