我有一个软件需要/bin/sh
Bash,但 Ubuntu 默认是 Dash,我想保留它作为默认设置;我不想永久地将其更改为 Bash。
有没有办法只针对正在运行的终端会话进行更改?那么在这个终端中运行的程序将看到/bin/sh
链接到 bash,但系统的其余部分仍将看到 Dash?或者我可以欺骗软件将其视为/bin/sh
Bash,即使它不是?
我没有编写这个软件,并且对其进行破解来/bin/bash
代替使用/bin/sh
并不是一个真正的选择。
答案1
如果是脚本,则只需调用该脚本即可
bash scriptname.sh
根本不需要更改链接。
对于已编译的可执行文件,你可以使用 chroot 路由:
mkdir rootfs
cp -a /usr rootfs/
cp -a /lib rootfs/
cp -a /lib64 rootfs/
cp /bin/bash rootfs/bin/sh
cp yourprogram rootfs/
sudo chroot rootfs sh
然后运行你的程序或sudo chroot rootfs /yourprogram
然而,实际上,没有理由不能使用/bin/bash
符号链接/bin/sh
。事实上,6.10 之前的版本Ubuntu 一直使用/bin/bash
,/bin/sh
后来他们改用 ,因为/bin/sh
它是 POSIX 的一个更快、更精简的实现/bin/sh
(即,它遵循 POSIX 标准,规定了类 Unix 操作系统实用程序和 OS 应如何运行并实现其一些内部功能),并且出于可移植性原因。我强烈推荐阅读 Gilles 的回答以及关于它是如何/bin/dash
产生的历史记录。至于兼容性,dash
使用 POSIX 功能编写的脚本将bash
完美地作为默认 shell 运行。通常,问题出在相反的情况——bash
具有 不需要的功能/bin/sh
,比如<<<
句法或数组。
此外,有问题的命令可能是为 RHEL 或 CentOS 编写的,它们确实使用 的/bin/bash
符号链接/bin/sh
,这表明了两点:它们可能针对特定的操作系统,并且不遵守 POSIX 原则。在这种情况下,检查命令还需要什么其他东西也是一个好主意,因为如果它真的是为另一个操作系统编写的,那么你可能会遇到比重新链接 更多的问题/bin/sh
。
答案2
两个答案已经建议了 chrooting 和 bind mounts,并且还有第三个密切相关的选项:挂载命名空间。使用unshare
程序,可以创建一个新的挂载命名空间,并且此命名空间内的挂载不会影响其他命名空间。
例如,在一个终端中,我执行:
muru|[0] ~ sudo unshare -m /bin/bash
root@muru-1604:~# sudo mount --bind /bin/bash /bin/sh
root@muru-1604:~# /bin/sh --version
GNU bash, version 4.4.18(1)-release (x86_64-pc-linux-gnu)
Copyright (C) 2016 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later
This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
root@muru-1604:~# sudo -iu muru
muru|[0] ~ /bin/sh --version # propagates
GNU bash, version 4.4.18(1)-release (x86_64-pc-linux-gnu)
Copyright (C) 2016 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later
This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
另一则消息:
$ /bin/sh --version
/bin/sh: 0: Illegal option --
因此,您可以在其自己的挂载命名空间中运行这个不灵活的程序。
答案3
一种可能性是绑定挂载单个文件。为此,您山文件/bin/bash
只是超过 /bin/dash
有点bash
像是覆盖或隐藏dash
。步骤如下(包括反向操作):
root@myhost:~# cd /bin
# situation before (bash and dash are different):
root@myhost:/bin# ls -l *sh*
-rwxr-xr-x 1 root root 1113504 Apr 4 20:30 bash
-rwxr-xr-x 1 root root 121432 Jan 25 2018 dash
lrwxrwxrwx 1 root root 4 Jul 13 11:38 sh -> dash
...
# mount /bin/bash over /bin/dash:
root@myhost:/bin# mount --bind /bin/bash /bin/dash
# situation now (bash and dash are the same):
root@myhost:/bin# ls -l *sh*
-rwxr-xr-x 1 root root 1113504 Apr 4 20:30 bash
-rwxr-xr-x 1 root root 1113504 Apr 4 20:30 dash
lrwxrwxrwx 1 root root 4 Jul 13 11:38 sh -> dash
...
# Now everything that runs `/bin/sh` in fact uses `/bin/bash`.
# check what the symlink "sh" says:
root@myhost:/bin# sh --version
GNU bash, version 4.4.19(1)-release (x86_64-pc-linux-gnu)
...
# undo the mount:
root@myhost:/bin# umount /bin/dash
# situation now (bash and dash are different again):
root@myhost:/bin# ls -l *sh*
-rwxr-xr-x 1 root root 1113504 Apr 4 20:30 bash
-rwxr-xr-x 1 root root 121432 Jan 25 2018 dash
lrwxrwxrwx 1 root root 4 Jul 13 11:38 sh -> dash
...
# check what the symlink "sh" now says:
root@myhost:/bin# sh --version
sh: 0: Illegal option --
我没有尝试mount --bind /bin/bash /bin/sh
直接隐藏
但是符号链接。上述mount
技巧只是使 bash 和 dash 相同,因此虽然它sh
指向 ,bash
但它引用
dash
。此外,这是一个系统范围的解决方案,而不仅仅是针对当前终端窗口。
我必须承认,这可能有点过头了,暂时更改符号链接要容易得多。我只是想展示另一种可能的方法。
答案4
您应该能够使用别名仅为当前会话更改它。在终端中运行命令之前:
alias sh=bash
这将是暂时的,并且仅在执行它的终端中有效。
但是:如果您的脚本使用绝对路径,则此方法将不起作用。
这个想法不错,但如果软件直接使用显式路径名调用 /bin/sh,它将无法工作。无论如何,该软件似乎没有经过精心设计,因此无法做出这样的假设。如果我不得不使用它,我可能会从准备和重置适当环境的脚本中运行它。– vanadium
不幸的是,“破解”脚本可能是你唯一的选择。根据与@vanadium的对话,你可以创建一个这样的包装器脚本:
#!/bin/bash
sudo ln -sf /bin/bash /bin/sh
/run/my/script
sudo ln -sf /bin/dash /bin/sh
但是,在脚本运行期间,最好希望系统上没有任何内容明确需要破折号。