2

我想从 NUL 分隔的输入(来自标准输入)创建一个 bash 数组。

这是一个例子:

## Let define this for clarity
$ hd() { hexdump -v -e '/1 "%02X "'; echo ;}
$ echo -en "A B\0C\nD\0E\0" | hd
41 20 42 00 43 0A 44 00 45 00

所以这是我的输入。

现在,如果不使用-aofread命令,使用 NUL 可以正常工作:

$ while read -r -d '' v; do echo -n "$v" | hd; done < <(echo -en "A B\0C\nD\0E\0")
41 20 42 
43 0A 44 
45 

我们得到正确的值。但我无法使用以下方法存储这些值-a

$ read -r -d '' -a arr < <(echo -en "A B\0C\nD\0E\0")
$ declare -p arr
declare -a arr='([0]="A" [1]="B")'

这显然不是我想要的。我想拥有:

$ declare -p arr
declare -a arr='([0]="A B" [1]="C
D" [2]="E")'

有没有办法去read -a,如果它不起作用,为什么?你知道一个简单的方法来做到这一点(避免while循环)吗?

4

4 回答 4

6

read -a正如您所注意到的,是错误的工作工具;它只支持非 NUL 分隔符。BashFAQ #1中给出了适当的技术:

arr=()
while IFS= read -r -d '' entry; do
  arr+=( "$entry" )
done

至于为什么 read -d '' -a是错误的工具:给出-d一个read参数来确定何时完全停止阅读,而不是何时停止阅读单个元素。

考虑:

while IFS=$'\t' read -d $'\n' words; do
  ...
done

...这将读取由制表符分隔的单词,直到它到达换行符。因此,即使使用read -a, using-d ''也会一直读取,直到达到 NUL 为止

您想要阅读的内容,直到没有更多内容可用并被 NUL 拆分,不是 NUL 的“-d”,而是根本没有行尾字符(和空的IFS)。这不是read当前可用的东西。

于 2014-05-05T13:55:45.867 回答
1

bash-4.4-alpha 添加了一个-d选项mapfile

`mapfile' 内置函数现在有一个 -d 选项来使用任意字符作为记录分隔符,以及一个 -t 选项来剥离与 -d 一起提供的分隔符。

https://tiswww.case.edu/php/chet/bash/CHANGES

使用它,我们可以简单地编写:

mapfile -t -d '' arr < <(echo -en "A B\0C\nD\0E\0")
于 2017-01-15T08:58:56.367 回答
0

如果有人想知道,这while是我用来存储NUL-separated值的函数(使用) stdin

read_array () {
    local i
    var="$1"
    i=0
    while read -r -d '' value; do
        printf -v "$var[$i]" "%s" "$value"
        i=$[$i + 1]
    done
}

然后可以非常干净地使用它:

$ read_array arr < <(echo -en "A B\0C\nD\0E\0")
$ declare -p arr
declare -a arr='([0]="A B" [1]="C
D" [2]="E")'
于 2014-05-05T14:59:58.413 回答
0

这是@vaab 函数的简化。它使用bash 4.3 的 nameref功能:

read_array () {
  local -n a=$1
  while read -r -d '' value; do
    a+=("$value")
  done
}

测试:

test_it () {
  local -a arr
  read_array arr < <(echo -en "A B\0C\nD\0E\0")
  declare -p arr
}
test_it
于 2017-01-15T08:51:44.980 回答