gpt4 book ai didi

bash - 将 IFS 设置为空字节不会在命令行中正确拆分行

转载 作者:行者123 更新时间:2023-11-29 09:03:06 25 4
gpt4 key购买 nike

~ ls
A B C

在 bash 上(看起来不对)

~IFS=$'\x00' read -a vars < <(find -type f -print0); echo "${vars}"
ABC

在 zsh 上(看起来不错)

~IFS=$'\x00' read -A vars < <(find -type f -print0); echo "${vars}"
A B C

这是一个 bash 错误吗?

最佳答案

null character很特别而且POSIX and bash do not allow it inside strings (它是字符串末尾的 定义,所以 $'\x00'$'\000' 几乎不起作用;Inian's answer 这里甚至链接到 workaround for entering the null character ,但同样你不能指望将其分配给变量时正确保存)。看起来 zsh 不介意,但 bash 不介意。

下面的测试说明了在文件名中表示空格、制表符和换行符的问题:

$ touch 'two words' tabbed$'\t'words "two
lines"
$ ls # GNU coreutils ls displays using bash's $'string' notation
'tabbed'$'\t''words' 'two'$'\n''lines' 'two words'
$ ls |cat # … except when piped elsewhere
tabbed words
two
lines
two words
$ find * # GNU findutils find displays tabs & newlines as questions
tabbed?words
two?lines
two words
$ find * |cat # … except when piped elsewhere
tabbed words
two
lines
two words
$ touch a b c # (more tests for later)

GNU 工具非常聪明并且知道这是一个问题,所以他们提出了创造性的方法来解决这个问题——但他们甚至都不一致。 ls假设您使用的是 bash 或 zsh(文字的 $'…' 语法 出现在 POSIX 中)和 find给你一个问号(它本身是一个有效的文件名字符,但它是一个匹配任何字符的文件 glob,所以例如 rm two?lines tabbed?words 将删除两个文件,就像 rm 'two'$'\n''lines' 'tabbed'$'\t''words' 一样)。当通过管道传输到另一个命令(如 cat)时,两者都会显示真相.

GNU/BSD/MacOSX/Busybox 查找和 xargs

我看到您正在使用 GNU 扩展:POSIX 和 BSD/OSX find不允许隐式路径和 POSIX find不支持 -print0虽然 POSIX find spec确实提到了:

Other implementations have added other ways to get around this problem, notably a -print0 primary that wrote filenames with a null byte terminator. This was considered here, but not adopted. Using a null terminator meant that any utility that was going to process find's -print0 output had to add a new option to parse the null terminators it would now be reading.

POSIX xargs spec同样缺乏对 -0 的支持(也没有对它的引用),尽管 xargs 支持它在 GNU、BSD/OSX 和 busybox 中。

因此,您或许可以这样做:

$ find . -type f -print0 |xargs -0
./c ./b ./a ./two
lines ./tabbed words ./two words

但是,您可能实际上想要数组,所以我可能过度拟合了您的简化问题。

map 文件

您可以使用 mapfile在 Bash 4.4 及更高版本中:

$ mapfile -d '' vars < <(find . -type f -print0)
$ printf '<%s>\n' "${vars[@]}"
<./c>
<./b>
<./a>
<./two
lines>
<./tabbed words>
<./two words>

一些命令,包括mapfile , read , 和 readarray (mapfile 的同义词),接受 -d ''好像是-d $'\0' ,可能是 [需要引用] 作为 POSIX shell 上述无法处理字符串中的空字符的解决方法。

mapfile命令仅将输入文件(在本例中为标准输入)读入 $vars由空字符分隔的数组。标准输入通过由 <(…) 创建的文件描述符通过管道填充。在行尾处理替换,它处理我们的 find 的输出命令。

旁白:你认为你可以简单地做 find … |mapfile …但这会改变范围,当管道命令完成时,您在其中设置或修改的任何变量都会丢失。流程替换技巧不会以同样的方式让您陷入困境。

printf命令只是演示数组的内容。尖括号表示每个项目的开始和结束,因此您不会被换行符、空格或制表符搞糊涂。

关于bash - 将 IFS 设置为空字节不会在命令行中正确拆分行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55015044/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com