为什么 Bash 在 Alpine 3.14.2 中无法正确评估可执行位?

为什么 Bash 在 Alpine 3.14.2 中无法正确评估可执行位?

在运行 Bash 5.1.4(1) 的 dockerized Alpine 3.14.2 中,我在 Bash 脚本中遇到了奇怪的行为。最重要的是测试文件的可执行性,但总是失败。简而言之,这是 if 测试:

bash-5.1# if [ ! -x /opt/java/openjdk/bin/java ]; then echo "something strange just happened"; fi
something strange just happened

但是,我所知道的多种“测试”可执行性的方法都显示出不同的结果:

bash-5.1# ls -la /opt/java/openjdk/bin/java
-rwxr-xr-x    1 root     root         12648 Jan 21  2021 /opt/java/openjdk/bin/java
bash-5.1# stat -c "%A" /opt/java/openjdk/bin/java
-rwxr-xr-x
bash-5.1# /opt/java/openjdk/bin/java --version
openjdk 15.0.2 2021-01-19
OpenJDK Runtime Environment AdoptOpenJDK (build 15.0.2+7)
OpenJDK 64-Bit Server VM AdoptOpenJDK (build 15.0.2+7, mixed mode, sharing)

为了让我的脚本正常工作,Bash 内的可执行性测试应该返回正确的结果。但为什么不呢?

我检查或尝试过一长串内容,其中一些是根据社区的建议进行的:

  • 检查失败了所有(测试的)可执行文件。甚至 Bash 本身。结果总是错误的:
bash-5.1# if [ ! -x /bin/bash ]; then echo "this is weird"; fi
this is weird
  • @KamilMaciorowski 建议在他的评论中测试 bash 覆盖。但输出看起来不错:
bash-5.1# type -a [
[ is a shell builtin
  • 这是命令的 strace(感谢@zevzek):
bash-5.1# strace -fe trace=access,faccessat,stat bash -c '[ -x /bin/bash ]'
stat("/root", {st_mode=S_IFDIR|0700, st_size=4096, ...}) = 0
stat(".", {st_mode=S_IFDIR|0700, st_size=4096, ...}) = 0
stat("/root", {st_mode=S_IFDIR|0700, st_size=4096, ...}) = 0
stat("/root", {st_mode=S_IFDIR|0700, st_size=4096, ...}) = 0
stat(".", {st_mode=S_IFDIR|0700, st_size=4096, ...}) = 0
stat("/usr/local/sbin/bash", 0x7ffc257ec050) = -1 ENOENT (No such file or directory)
stat("/usr/local/bin/bash", 0x7ffc257ec050) = -1 ENOENT (No such file or directory)
stat("/usr/sbin/bash", 0x7ffc257ec050)  = -1 ENOENT (No such file or directory)
stat("/usr/bin/bash", 0x7ffc257ec050)   = -1 ENOENT (No such file or directory)
stat("/sbin/bash", 0x7ffc257ec050)      = -1 ENOENT (No such file or directory)
stat("/bin/bash", {st_mode=S_IFREG|0755, st_size=760136, ...}) = 0
stat("/bin/bash", {st_mode=S_IFREG|0755, st_size=760136, ...}) = 0
+++ exited with 1 +++
  • 使用 Busybox 中的“real”[效果很好,但不能[在 Bash 中使用。但我不可能重写该容器中软件附带的所有 Bash 脚本:
bash-5.1# which [
/usr/bin/[
bash-5.1# if [ ! -x /bin/bash ]; then echo "this is weird"; fi
this is weird
bash-5.1# if /usr/bin/[ ! -x /bin/bash ]; then echo "this is weird"; fi
bash-5.1#
  • 文件系统未安装“noexec”(仅安装您期望的文件系统,例如 /proc)

  • 其他测试如[ -f /bin/bash ][ -f /tmp/not_there ]是正确的,只是-x看起来有问题

  • 我尝试了 Bash 5.1.1 并且它在那里工作。然后我经历了Bash 发行说明,但我找不到两者之间相关的任何内容。

答案1

Alpine 3.14 似乎与这里的一个已知错误有关。所有技术细节都是已经的一部分那里有未解决的问题(我最初没有找到,因为我一直在寻找“可执行”位)。

简而言之,暂时不要在 Alpine 3.14 中使用 Bash。

长的答案是更新受影响的特定组件集,这在 Docker 环境中大多数时候是不切实际的。

相关内容