如何将制表符分隔行读入变量

how to read tab separated line into variables

我在zsh中写了这个函数

function test() {
  test="a\tb\tc"

  while IFS=$'\t' read -r user host key; do
    echo "user: $user"
    echo "host: $host"
    echo "key: $key"
  done <<< "$test"
}

输出为:

user: a b   c
host:
key:

如果而不是

... IFS=$'\t' read -r ...

我改成

... IFS='\t' read -r ...

输出是

user: a
host:
key: b  c

到底是怎么回事?

我想阅读制表符分隔行并相应地设置我的变量。

将 double-quotes 更改为 $'...'(单引号前面有 $)可以挽救变量 $test:

test=$'a\tb\tc'

这是 QUOTING(double-quoting 和 $'...')的 zsh 手册:

QUOTING
...
A string enclosed between $' and ' is processed the same way as the string arguments of the print builtin
...
Inside double quotes (""), parameter and command substitution occur, and \ quotes the characters \, `, ", $, and the first character of $histchars (default !).

--- zshmisc(1), QUOTING

例如:

  • "$" -> $, "\!" -> !
  • "\t" -> \t(zsh 不识别为 tab),"\a" -> \a等等

它不会将转义序列\t当成tab当它用在双引号内时,所以"a\tb\tc"并不意味着“atabbtabc"。 (但事情有点复杂:内置 echo 识别转义序列 \t。)

(1) ... IFS=$'\t' read -r ...(原形)

因为扩展 "$test" 没有任何 tab 字符,所以 read 将整行分配给 $user:

user: a b   c
host:
key:

(但是 echo 将转义序列 \t 识别为 制表符 。)

(2) ... IFS='\t' read -r ...

同样,扩展 "$test" 没有任何 tab 字符,因此 read\ 和 [=52= 分隔字段] 根据 $IFSa\t\b\tc拆分为a(到$user),\(分隔符),``(空到$host),t(分隔符) ,以及该行的其余部分(b\tc$key):

user: a
host:
key: b  c

(但同样,echo 将转义序列 \t 识别为 制表符 。)


这是代码从 test="..." 更改为 test=$'...':

function test() {
  test=$'a\tb\tc'

  while IFS=$'\t' read -r user host key; do
    echo "user: $user"
    echo "host: $host"
    echo "key: $key"
  done <<< "$test"
}
test

输出为:

user: a
host: b
key: c

PS:值得一读POSIX的引用规范,比zsh的(https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_02)

更简单