临时更改 /bin/sh 链接

临时更改 /bin/sh 链接

我有一个软件需要/bin/shBash,但 Ubuntu 默认是 Dash,我想保留它作为默认设置;我不想永久地将其更改为 Bash。

有没有办法只针对正在运行的终端会话进行更改?那么在这个终端中运行的程序将看到/bin/sh链接到 bash,但系统的其余部分仍将看到 Dash?或者我可以欺骗软件将其视为/bin/shBash,即使它不是?

我没有编写这个软件,并且对其进行破解来/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

但是,在脚本运行期间,最好希望系统上没有任何内容明确需要破折号。

相关内容