bash 映射文件 NUL 错误?

cas*_*cas 2 bash null

bashmapfile在处理 NUL 分隔输入时似乎被破坏了。特别是,它无法-正确处理减号字符 ( ),将 1 后的空字符串视为行尾标记。

例如:

#!/bin/bash

mkdir /tmp/junk
cd /tmp/junk

touch a.txt b.txt c.txt d-e-f.txt
declare -a files

echo "mapfile using default \\n delimiter"
mapfile -t  files < <(find . -maxdepth 1 -type f -name '*.txt')
typeset -p files

echo
echo "mapfile using NUL delimiter"
mapfile -d'' -t  files < <(find . -maxdepth 1 -type f -name '*.txt' -print0)
typeset -p files

echo
echo "and again"
mapfile -d$'\0' -t  files < <(find . -maxdepth 1 -type f -name '*.txt' -print0)
typeset -p files
Run Code Online (Sandbox Code Playgroud)
$ ./test.sh 
mapfile using default \n delimiter
declare -a files=([0]="./d-e-f.txt" [1]="./a.txt" [2]="./c.txt" [3]="./b.txt")

mapfile using NUL delimiter
declare -a files=([0]="./d-" [1]="e-" [2]="f.txt")

and again
declare -a files=([0]="./d-" [1]="e-" [2]="f.txt")
Run Code Online (Sandbox Code Playgroud)

这是一个错误吗?或者我忘记了一些重要的事情并且只是做错了?

中的映射文件条目man bash说:

-ddelim 的第一个字符用于终止每个输入行,而不是换行符。 如果 delim 是空字符串,mapfile 将在读取 NUL 字符时终止一行

bash 版本是5.1.8(1)-release

$ bash --version
GNU bash, version 5.1.8(1)-release (x86_64-pc-linux-gnu)
Copyright (C) 2020 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>

This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Run Code Online (Sandbox Code Playgroud)
更新

更奇怪的是,如果数组已经存在,它似乎会破坏数组的现有元素(如上所示),但如果不存在,甚至不会创建它。

$ unset files
$ mapfile -t -d'' files < <(find . -maxdepth 1 -type f -name '*.txt' -print0)
$ typeset -p files
-bash: typeset: files: not found
Run Code Online (Sandbox Code Playgroud)

Rob*_*ade 5

来自bash 手册中有关分词的部分

显式空参数(""'')将被保留并作为空字符串传递给命令。[...] 该单词在分词和删除空参数之后-d''变成。-d

args在工具箱中放置一个 shell 脚本来解决参数处理问题会很有帮助。这是一种可能的实现:

#!/bin/sh
printf "%d args:" "$#"
test "$#" -gt 0 && printf " <%s>" "$@"
echo

# Source:
# https://lists.gnu.org/archive/html/help-bash/2021-07/msg00044.html
Run Code Online (Sandbox Code Playgroud)

尝试一下mapfile -d'' -t files

$ args mapfile -d'' -t files
4 args: <mapfile> <-d> <-t> <files>
Run Code Online (Sandbox Code Playgroud)

我们看到我们认为传递给该-d选项的 NUL 并不存在。该-d选项的参数是命令行上的下一个参数:-t!

[link]-d选项的文档说:mapfile

delim的第一个字符用于终止每个输入行

的第一个字符-t-

因此这两个调用是等价的:

mapfile -d'' -t files
mapfile -d '-' files
Run Code Online (Sandbox Code Playgroud)

这解释了您所经历的结果。