我有一堆 shell 脚本,它们错误地认为/bin/sh
等同于/bin/bash
.例如,他们有#!/bin/sh
shebang,但使用source
命令而不是.
(点)。
我运行 Ubuntu 16,其中/bin/sh
链接到dash
,因此不支持 bash-isms。
我需要定期运行脚本。另外,我有时需要从原作者处更新它们,而原作者并不想修复这个特定的错误。我想避免修复所有这些文件(其中有很多文件,它们不是我的,更新后我将丢失所有更改)。另外,我想避免对系统进行全局更改,因为它可能会破坏其他脚本。
有没有办法以某种方式创建一个/bin/sh
指向 bash 的(临时或非临时)环境,用于这些脚本,同时不接触全局系统/bin/sh
?
答案1
我想挂载命名空间或类似的东西可以用来安排不同的进程/用户对是什么有不同的想法/bin/sh
。
但这听起来很黑客,也可以算作“对系统进行永久性更改”。仅进行一行修复可能会更容易。使该修复成为更新过程的一部分,并发布错误报告和有关错误的 hashbang 上游的补丁。
对于 GNU sed
,应该这样做来修复它们:
sed -i -e '1s,^#! */bin/sh,#!/bin/bash,' /all/the/scripts/*
答案2
如果/bin/sh
->/bin/dash
在你的系统上是一个动态链接的可执行文件,就像在我的系统上一样(你可以使用 file(1) 检查它),你可以使用 hackLD_PRELOAD
来实现。
它的工作原理如下:加载一个小型动态库覆盖LD_PRELOAD
glibc __libc_start_main
(调用可执行文件函数的函数main()
),然后使用相同的参数argv[0] == /bin/sh
执行 exec /bin/bash
(除了argv[0]
);否则它会调用原始内容__libc_start_main
,就好像什么也没发生一样。
$ cat sh_is_bash.c
#define _GNU_SOURCE /* for RTLD_NEXT */
#include <string.h>
#include <unistd.h>
#include <dlfcn.h>
#include <err.h>
int __libc_start_main(
int (*main)(int,char**,char**), int ac, char **av,
int (*init)(int,char**,char**), void (*fini)(void),
void (*rtld_fini)(void), void *stack_end)
{
typeof(__libc_start_main) *real_lsm;
if(ac > 0 && !strcmp(av[0], "/bin/sh")){
av[0] = "/bin/bash";
execv(av[0], av);
err(1, "execv %s", av[0]);
}else if(real_lsm = dlsym(RTLD_NEXT, "__libc_start_main"))
return real_lsm(main, ac, av, init, fini, rtld_fini, stack_end);
else
errx(1, "BUG: dlsym: %s", dlerror());
}
$ cc -fPIC -shared -Wall -W -Wno-parentheses sh_is_bash.c -o sh_is_bash.so -ldl
$ LD_PRELOAD=`pwd`/sh_is_bash.so program ...
任何带有 shebang 的脚本都将在环境变量包含 的绝对路径时执行,而不是#! /bin/sh
执行。/bin/bash
/bin/sh
LD_PRELOAD
sh_is_bash.so
这很丑陋,但它不需要对系统或脚本进行任何硬更改,它很容易部署和管理,并且不需要任何特殊权限。
答案3
您可以轻松修复它们,而不会破坏您的系统!
find . -name '*.sh' -type f -exec sed -i '1s|^#! */bin/sh|#!/bin/bash|' {} +
答案4
在您的情况下,包含非 POSIX 扩展的脚本应该具有相关的正确#!
标头:
#!/bin/bash
所以我认为没有办法编辑所有不正确的脚本。
顺便说一句:如果你真的确定,你可以创建一个 bash 的临时链接并重命名它:
cd /bin
ln -s bash nsh
mv nsh sh
由于mv
以原子方式工作,这将确保始终有一个工作/bin/sh
因此,重命名时当前运行的脚本和其他 shell 将继续工作,并且重命名后,这将调用 bash 而不是 dash。
但是,如果您的系统以允许编辑脚本的方式运行,我宁愿只编辑脚本。
如果您替换/bin/sh
为 的链接bash
,请不要忘记修复此问题,以便在完成后再次/bin/sh
成为 的链接。dash
如果有问题的脚本是二进制数据包的一部分,请不要忘记向上游提交针对该问题的错误报告。