bash 映射文件 NUL 错误?

bash 映射文件 NUL 错误?

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
$ ./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")

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

中的映射文件条目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.

更新

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

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

答案1

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

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

$ args mapfile -d'' -t files
4 args: <mapfile> <-d> <-t> <files>

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

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

第一个字符德利姆用于终止每个输入行

的第一个字符-t-

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

mapfile -d'' -t files
mapfile -d '-' files

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

相关内容