为什么使用“while''IFS=,read -r part''”无法将逗号分隔的字符串拆分为两部分?

5

因为IFS变量的默认值是换行符/制表符/空格,所以以下代码:

while read -r line
do
    echo $line
done <<< "hello\nworld"

输出:

hello
world

所以这段代码:

while IFS=',' read -r part
do
    echo $part
done <<< "hello,world"

但是这个只会输出:
hello,world

我原本希望它打印出与之前脚本相同的结果。

我在这里漏掉了什么?


3
“help read”:从标准输入读取一行[...]该行被分成字段[...]任何剩余的单词都分配给最后一个NAME。 - jhnc
1
“read” 只填充一个变量,因此不会发生拆分。 话虽如此,您的第一个循环应该只输出 hello\nworld。 您的输入字符串是包含两个字符 \n 的一行,而不是两行。 - chepner
1
@chepner,看起来OP正在运行某个具有类似XPG行为的地方,并且该位置正在使用echo\n替换为换行符本身(这很奇怪,因为在bash中这绝不是默认设置)。 - Charles Duffy
@yoyobara,你的脚本是以#!/bin/bash开头还是通过bash yourscript运行的?如果你的解释器不是bash(例如,如果它是sh),那么这就可以解释echo的行为之谜了。 - Charles Duffy
1个回答

6

回答“为什么”问题

IFS是字段分隔符,而不是记录分隔符(默认记录分隔符是换行符,可以使用-d参数更改为read)。每次调用read都会读取一个记录,并在字段边界可选地将其拆分成多个变量。

当你运行read -r part时,你只读取一个记录(进入part的记录),因此没有分隔要做:因此$part包含整个记录,包括逗号。


处理IFS的替代方案

相比之下,如果您使用-a指定目标作为数组(read -r -a parts)或传递多个目标变量(read -r part1 part2 part3),则会进行字段拆分。

与以下进行比较:

while IFS=, read -r key value; do
  echo "key=$key, value=$value"
done <<EOF
hello,world
hi,neighbor
EOF

同样地,可以将一行读入一个数组:

while IFS=, read -r -a parts; do          # split on comma into array
  printf 'Read %d parts: ' "${#parts[@]}" # count items in array
  printf '<%s> ' "${parts[@]}"            # print those items in arrow brackets
  printf '\n'
done <<EOF
three,word,array
this,is,four,words
EOF

...预期产生:

Read 3 parts: <three> <word> <array> 
Read 4 parts: <this> <is> <four> <words> 

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接