bash while/read 循环在基于 mips/musl/busybox 的虚拟机中表现不同

bash while/read 循环在基于 mips/musl/busybox 的虚拟机中表现不同

在 qemu (mips) 中运行的基于 musl/busybox 的系统上,该脚本

#!/usr/bin/bash

printf '%s\n' "${BASH_VERSION}"

> test.txt
echo 'test.txt:'
cat test.txt

echo "No process substitution:"
while IFS= read -r i; do
    printf 'ABC %s\n' $i | cat -vet
done < test.txt

echo 'test.txt:'
cat test.txt

echo "Process substitution:"
while IFS= read -r i; do
    printf 'ABC %s\n' $i | cat -vet
done < <(cat test.txt)

echo 'test.txt:'
cat test.txt

echo "Pipes:"
cat test.txt | while IFS= read -r i; do
    printf 'ABC %s\n' $i | cat -vet
done

echo 'test.txt:'
cat test.txt

echo "Why???"

印刷

4.3.42(1)-release
test.txt:
No process substitution:
test.txt:
Process substitution:
ABC $
test.txt:
Pipes:
ABC $
test.txt:
Why???

在 Arch Linux 机器上,使用相同版本的 bash,它会打印

4.3.42(1)-release
test.txt:
No process substitution:
test.txt:
Process substitution:
test.txt:
Pipes:
test.txt:
Why???

请注意,基于 musl/busybox 的系统为进程替换示例打印“ABC”字符串,而 x86_64 框则不会。> test.txt如果我替换为 , 该脚本在两个系统上的行为相同echo 'some text' > test.txt

我很困惑为什么脚本在一个盒子上打印“ABC”,但在另一个盒子上却没有,以及为什么它只在某些条件下才这样做(到目前为止,管道和进程替换示例)。我很想知道是什么导致了行为的改变 - 是由 bash 引起的吗? coreutils/busybox?库?一些环境变量?还有什么我没想到的吗?行为的改变是有意的(如果是的话,指向一些文档的指针会有所帮助),还是一个错误?我是否配置错误?

故障排除建议会很好,甚至可以礼貌地指出其他更适合该问题的地方。我会发布到邮件列表,但我不确定是什么导致了这种行为,所以我不知道应该发布到哪个邮件列表。因此,我认为一个更通用的论坛是合适的 - 如果我错了,我很乐意得到纠正。


编辑:

VM 和 Arch 盒子都已将 bash-4.3.042 安装(通过 pacman;在 VM 上它是自定义 PKGBUILD)到 /usr/bin/bash。 Arch box 使用 glibc 和 GNU coreutils,在 x86_64 笔记本电脑上运行,而 VM 是基于 musl 和 busybox 的系统,在 qemu (qemu-system-mips) 中运行。我尝试使用 PATH 中的 busybox 实用程序在 Arch 盒子上运行测试脚本,这似乎没有改变任何东西。由此,我假设虚拟机上的 bash 是问题所在,因为我相信唯一涉及的非内置是“cat”。我还尝试通过 qemu-mips 在 Arch 盒子上使用 bash 二进制文件(它是静态链接的)运行脚本,并得到与在 VM 中运行它相同的结果(为管道和进程替换示例打印“ABC ”) ,这似乎支持了虚拟机中的 bash 二进制文件有问题的假设。我假设 bash 的行为应该与 Arch 盒子上的行为一样;稍后我会尝试为此做一些测试。

评论中的建议之一是发布od -cb < <(cat test.txt)和的输出od -cb <(cat test.txt),大概是为了看看两者之间是否存在差异。为了尝试覆盖所有基础,我尝试了几个不同的版本:

在 Arch 盒子上:

$ od -cb < <(cat test.txt)
0000000
$ od -cb <(cat test.txt)
0000000
$ od -cb < test.txt
0000000
$ cat test.txt | od -cb
0000000
$ # Just to show that od is actually working...
$ od -cb < <(echo 'yes')
0000000   y   e   s  \n
        171 145 163 012
0000004

使用虚拟机中的 bash(通过 qemu-mips):

$ od -cb < <(cat test.txt)
0000000
$ od -cb <(cat test.txt)
0000000
$ od -cb < test.txt
0000000
$ cat test.txt | od -cb
0000000
$ # Just to show that od is actually working...
$ od -cb < <(echo 'yes')
0000000   y   e   s  \n
        171 145 163 012
0000004

使用 busybox 的 od(都在虚拟机中,使用 bash 二进制文件(通过 qemu-mips)和系统 bash):

$ od -cb < <(cat test.txt)
$ od -cb <(cat test.txt)
$ od -cb < test.txt
$ cat test.txt | od -cb
$ # Just to show that od is actually working...
$ od -cb < <(echo 'yes')
0000000    y   e   s  \n                                                
         171 145 163 012                                                
0000004

所以这似乎是符合预期的。

编辑:

VM 上的 bash 静态链接到 musl 1.1.12,并使用内部 readline 构建。为了确保 bash 版本的配置尽可能相似,我测试了 Arch 打包的 bash 和使用内部 readline 的构建(两者的行为相同);两者都与 glibc 动态链接。

为了证明它实际上是两台机器上的 bash:

拱形箱:

$ /usr/bin/bash --version
GNU bash, version 4.3.42(1)-release (x86_64-unknown-linux-gnu)
Copyright (C) 2013 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.

虚拟机:

/usr/bin/bash --version
GNU bash, version 4.3.42(1)-release (mips-unknown-linux-musl)
Copyright (C) 2013 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.

一些背景;我试图让一个相当复杂的 bash 脚本在基于 musl/busybox 的系统上运行而不会出现错误,但是脚本的一部分包含由进程替换提供的 while 循环。在基于 musl/busybox 的系统上,意外地提供了一个空输入(在示例中,$i == "")。我可以解决这个问题,但我更想了解为什么它不能按我的预期工作。

答案1

观察到的行为是 bash 中的一个错误,由没有作业控制支持的 bash 构建触发。因为我是交叉编译的,所以作业控制的配置检查默认为“缺失”(我应该告诉配置要使用什么,请参阅CLFS)。这邮件列表报告测试用例集有所减少,并且在那周的开发分支中修复可能会感兴趣。具体修复是更改为 subst.c

相关内容