WSL2 发行版 shell 无法启动从外部复制的文件
WSL2 distro shell can't launch a file copied from outside
简述情况
我无法在 WSL2 发行版中启动可执行文件(二进制或脚本),如果它不是在该发行版中创建的话
我可以启动在发行版 shell 中创建的脚本和二进制文件(不以任何方式使用 /mnt/c 或 /mnt/d)
但我无法启动在外部创建并从 Windows 内部复制的任何内容(使用 /mnt/c 或 /mnt/d)
我可以在文件系统中看到复制的文件,可以“cat”它们,可以用“which”查找它们,但是我无法通过在命令行中输入路径来启动它们
我对这一切的疑问
- 为什么 shell 在使用 shell 中的 运行 时看不到文件?
- 如何让 shell 看到从外部复制的文件?
- 如果我无法让 shell 启动文件,那么我该如何启动它们?
详细情况
我有 Windows 10 个 WSL2 和两个发行版
- Ubuntu-20.04
- 高山
在 Ubuntu 我有一个“Hello, World!”用 C 编写的项目
它在 Ubuntu 中编译,然后在 Ubuntu 中编译 运行 就好了
但是,当我将它从 Ubuntu 复制到 Windows
cp hello /mnt/d/
然后去Alpine里面从Windows
复制进去
cp /mnt/d/hello .
然后我无法在 Alpine 中启动它
这是 Ubuntu 中 file hello
命令的输出,带有一些额外的格式(以防万一)
$ file hello
hello:
ELF 64-bit LSB shared object,
x86-64,
version 1 (SYSV),
dynamically linked,
interpreter /lib64/ld-linux-x86-64.so.2,
BuildID[sha1]=021352ab7bf244e340c3c42ce34225b74baa6618,
for GNU/Linux 3.2.0,
not stripped
这是我在 Alpine 所拥有的
$ cp /mnt/d/hello .
$ ls -l
-rwxr-xr-x 1 pavel pavel 16760 Apr 19 19:07 hello
$ ./hello
-ash: ./hello: not found
现在与从 Windows
复制的脚本相同
从Windows
复制Alpine里面的脚本
$ cp /mnt/d/hello.sh .
检查内容
$ cat hello.sh
#!/bin/ash
echo Hello!
设置执行权限以防万一
$ chmod agu+x hello.sh
正在尝试 运行 它
$ ./hello.sh
-ash: ./hello.sh: not found
但是,我可以通过显式调用 ash 工具并将脚本路径作为参数传递来启动 hello.sh
$ ash ./hello.sh
Hello!
同时,在 Alpine 运行s 中创建的脚本只需输入它的命令行路径
$ cat << EOF > hello-local.sh
> #!/bin/ash
> echo Local hello!
> EOF
$ chmod agu+x hello-local.sh
$ ./hello-local.sh
Local hello!
此外,我无法通过使用 cp
复制一个不会 运行 的文件
cp hello.sh hello2.sh
或者用 cat
复制它
cat hello.sh > hello3.sh
cmod agu+x hello3.sh
为什么我需要从外面复制东西
一切始于我想探索 Docker for Windows 如何使用 Linux 命名空间来分隔容器
Docker for Windows 使用的发行版称为 docker-desktop
docker-desktop 发行版既没有我实验所需的实用程序,也没有获取这些实用程序的包管理器
所以我试着从外面复制它们
但现在 Docker Windows 研究并不是唯一的问题
我想了解这种正在发生的魔法同样糟糕
公平地说,这里确实有三个独立的问题,但不一定是您在 post:
中列出的问题
第二个问题 -- 为什么您复制到 Alpine 的脚本会失败?
正如@MarkPlotnick 在评论中所提到的(并且您已确认),这是由于脚本具有 DOS/Windows 行结尾 (CRLF)。一般来说,尽量避免使用 Windows 工具创建或编辑 Linux 文本文件,除非您确定他们正在使用 Linux line-endings.
第二个问题 -- 为什么在 Ubuntu 上编译并将二进制文件复制到 Alpine 时,您的 C 程序会失败?
还有@MarkPlotnick在评论中提到的,这是因为Ubuntu默认使用glibc
作为标准库实现,而Alpine使用musl
。请参阅按“相关性”排序的列表中的 a number of questions here for more information. The first one 实际上是一个很好的开始。
主要问题 -- 如何探索 docker-desktop
发行版
实际上,您的主要目标似乎是如何访问 docker-desktop
发行版中的某些工具以了解更多信息。
我本来想说“不要”(有更多解释),但事实是我认为这是一种潜在的良好学习体验。在某种程度上,我已经做到了,那么我有什么资格说它“太危险”或建议不要这样做呢? ;-)
不过,我会给出合理的警告 -- docker-desktop 发行版并非 打算 由用户 运行 发行。 Docker Desktop 将链接和套接字“注入”到您的其他 WSL2 发行版(您可以在 Docker Desktop 中 enable/disable per-distro),以便其工具、进程等适用于您的所有 WSL2(和 PowerShell/CMD)实例。
我个人会尽量避免对 docker-desktop
发行版本身进行任何 更改。当 Docker Desktop 提取新的 rootfs 时,它们可能会被覆盖。
但是,我们仍然可以通过 从 另一个发行版访问它们来访问我们需要的工具,而不是将它们复制 到 docker-desktop.
首先,请注意——我想您可能已经发现,docker-desktop 也是 musl
-basesd。因此,您需要使用来自另一个基于 musl
的发行版(例如 Alpine)的工具。
这可以通过 运行 在您的 Alpine 实例中(作为 root)执行一次以下行来轻松完成:
echo "/ /mnt/wsl/instances/Alpine none defaults,bind,X-mount.mkdir 0 0" >> /etc/fstab
这会将 Alpine 实例的挂载添加到 tmpfs /mnt/wsl
挂载中。您可以查看 my Super User answer here 了解更多详细信息。
一旦 wsl --terminate Alpine
并重新启动它,您就可以从任何其他 WSL2 发行版访问 Alpine 文件。
作为一个有用的(为了您的意图)示例,在 Alpine 中安装 util-linux
包以访问 lsns
命令。
然后,在 docker-desktop 发行版中(我假设您已经知道使用 wsl -u root -d docker-desktop
进行访问,但我将在此处包含该命令以供其他未来的读者使用),以列出命名空间:
/mnt/host/wsl/instances/Alpine/usr/bin/lsns
docker-desktop 实例自动挂载到与默认目录略有不同的目录(参见 cat /etc/wsl.conf
),因此您需要将路径调整为 /mnt/host/wsl
而不是 /mnt/wsl
。
但是有了它,您可以 运行 直接在 docker-desktop 中 运行 所有(大部分?)您的 Alpine 二进制文件,而无需直接修改它。如果您的主目录中有一个脚本,您希望在 docker-desktop 中 运行,例如:
/mnt/host/wsl/instances/Alpine/home/users/<yourusername>/hello.sh
请注意,如果您的二进制文件需要 Alpine 上的 dynamically-linked 库,我假设您需要相应地调整 LD_LIBRARY_PATH
,尽管我还没有测试过。例如:
LD_LIBRARY_PATH=/mnt/host/wsl/instances/Alpine/usr/lib /mnt/host/wsl/intances/Alpine/usr/bin/<whatever>
简述情况
我无法在 WSL2 发行版中启动可执行文件(二进制或脚本),如果它不是在该发行版中创建的话
我可以启动在发行版 shell 中创建的脚本和二进制文件(不以任何方式使用 /mnt/c 或 /mnt/d)
但我无法启动在外部创建并从 Windows 内部复制的任何内容(使用 /mnt/c 或 /mnt/d)
我可以在文件系统中看到复制的文件,可以“cat”它们,可以用“which”查找它们,但是我无法通过在命令行中输入路径来启动它们
我对这一切的疑问
- 为什么 shell 在使用 shell 中的 运行 时看不到文件?
- 如何让 shell 看到从外部复制的文件?
- 如果我无法让 shell 启动文件,那么我该如何启动它们?
详细情况
我有 Windows 10 个 WSL2 和两个发行版
- Ubuntu-20.04
- 高山
在 Ubuntu 我有一个“Hello, World!”用 C 编写的项目
它在 Ubuntu 中编译,然后在 Ubuntu 中编译 运行 就好了
但是,当我将它从 Ubuntu 复制到 Windows
cp hello /mnt/d/
然后去Alpine里面从Windows
复制进去cp /mnt/d/hello .
然后我无法在 Alpine 中启动它
这是 Ubuntu 中 file hello
命令的输出,带有一些额外的格式(以防万一)
$ file hello
hello:
ELF 64-bit LSB shared object,
x86-64,
version 1 (SYSV),
dynamically linked,
interpreter /lib64/ld-linux-x86-64.so.2,
BuildID[sha1]=021352ab7bf244e340c3c42ce34225b74baa6618,
for GNU/Linux 3.2.0,
not stripped
这是我在 Alpine 所拥有的
$ cp /mnt/d/hello .
$ ls -l
-rwxr-xr-x 1 pavel pavel 16760 Apr 19 19:07 hello
$ ./hello
-ash: ./hello: not found
现在与从 Windows
复制的脚本相同从Windows
复制Alpine里面的脚本$ cp /mnt/d/hello.sh .
检查内容
$ cat hello.sh
#!/bin/ash
echo Hello!
设置执行权限以防万一
$ chmod agu+x hello.sh
正在尝试 运行 它
$ ./hello.sh
-ash: ./hello.sh: not found
但是,我可以通过显式调用 ash 工具并将脚本路径作为参数传递来启动 hello.sh
$ ash ./hello.sh
Hello!
同时,在 Alpine 运行s 中创建的脚本只需输入它的命令行路径
$ cat << EOF > hello-local.sh
> #!/bin/ash
> echo Local hello!
> EOF
$ chmod agu+x hello-local.sh
$ ./hello-local.sh
Local hello!
此外,我无法通过使用 cp
复制一个不会 运行 的文件cp hello.sh hello2.sh
或者用 cat
复制它cat hello.sh > hello3.sh
cmod agu+x hello3.sh
为什么我需要从外面复制东西
一切始于我想探索 Docker for Windows 如何使用 Linux 命名空间来分隔容器
Docker for Windows 使用的发行版称为 docker-desktop
docker-desktop 发行版既没有我实验所需的实用程序,也没有获取这些实用程序的包管理器
所以我试着从外面复制它们
但现在 Docker Windows 研究并不是唯一的问题
我想了解这种正在发生的魔法同样糟糕
公平地说,这里确实有三个独立的问题,但不一定是您在 post:
中列出的问题第二个问题 -- 为什么您复制到 Alpine 的脚本会失败?
正如@MarkPlotnick 在评论中所提到的(并且您已确认),这是由于脚本具有 DOS/Windows 行结尾 (CRLF)。一般来说,尽量避免使用 Windows 工具创建或编辑 Linux 文本文件,除非您确定他们正在使用 Linux line-endings.
第二个问题 -- 为什么在 Ubuntu 上编译并将二进制文件复制到 Alpine 时,您的 C 程序会失败?
还有@MarkPlotnick在评论中提到的,这是因为Ubuntu默认使用glibc
作为标准库实现,而Alpine使用musl
。请参阅按“相关性”排序的列表中的 a number of questions here for more information. The first one 实际上是一个很好的开始。
主要问题 -- 如何探索 docker-desktop
发行版
实际上,您的主要目标似乎是如何访问 docker-desktop
发行版中的某些工具以了解更多信息。
我本来想说“不要”(有更多解释),但事实是我认为这是一种潜在的良好学习体验。在某种程度上,我已经做到了,那么我有什么资格说它“太危险”或建议不要这样做呢? ;-)
不过,我会给出合理的警告 -- docker-desktop 发行版并非 打算 由用户 运行 发行。 Docker Desktop 将链接和套接字“注入”到您的其他 WSL2 发行版(您可以在 Docker Desktop 中 enable/disable per-distro),以便其工具、进程等适用于您的所有 WSL2(和 PowerShell/CMD)实例。
我个人会尽量避免对 docker-desktop
发行版本身进行任何 更改。当 Docker Desktop 提取新的 rootfs 时,它们可能会被覆盖。
但是,我们仍然可以通过 从 另一个发行版访问它们来访问我们需要的工具,而不是将它们复制 到 docker-desktop.
首先,请注意——我想您可能已经发现,docker-desktop 也是 musl
-basesd。因此,您需要使用来自另一个基于 musl
的发行版(例如 Alpine)的工具。
这可以通过 运行 在您的 Alpine 实例中(作为 root)执行一次以下行来轻松完成:
echo "/ /mnt/wsl/instances/Alpine none defaults,bind,X-mount.mkdir 0 0" >> /etc/fstab
这会将 Alpine 实例的挂载添加到 tmpfs /mnt/wsl
挂载中。您可以查看 my Super User answer here 了解更多详细信息。
一旦 wsl --terminate Alpine
并重新启动它,您就可以从任何其他 WSL2 发行版访问 Alpine 文件。
作为一个有用的(为了您的意图)示例,在 Alpine 中安装 util-linux
包以访问 lsns
命令。
然后,在 docker-desktop 发行版中(我假设您已经知道使用 wsl -u root -d docker-desktop
进行访问,但我将在此处包含该命令以供其他未来的读者使用),以列出命名空间:
/mnt/host/wsl/instances/Alpine/usr/bin/lsns
docker-desktop 实例自动挂载到与默认目录略有不同的目录(参见 cat /etc/wsl.conf
),因此您需要将路径调整为 /mnt/host/wsl
而不是 /mnt/wsl
。
但是有了它,您可以 运行 直接在 docker-desktop 中 运行 所有(大部分?)您的 Alpine 二进制文件,而无需直接修改它。如果您的主目录中有一个脚本,您希望在 docker-desktop 中 运行,例如:
/mnt/host/wsl/instances/Alpine/home/users/<yourusername>/hello.sh
请注意,如果您的二进制文件需要 Alpine 上的 dynamically-linked 库,我假设您需要相应地调整 LD_LIBRARY_PATH
,尽管我还没有测试过。例如:
LD_LIBRARY_PATH=/mnt/host/wsl/instances/Alpine/usr/lib /mnt/host/wsl/intances/Alpine/usr/bin/<whatever>