/bin/sh
と同じだと誤って考えるシェルスクリプトがたくさんあります。たとえば、shebangが/bin/bash
ありますが(ドット)の代わりにコマンドを使用します。#!/bin/sh
source
.
/bin/sh
に接続されているUbuntu 16を実行しているため、dash
bash-ismsはサポートされていません。
定期的にスクリプトを実行する必要があります。また、時にはこの特定のバグを修正したくない原作者から更新する必要がある場合もあります。これらのファイルをすべて変更することを避けたいです(ファイルが多く、私のものではなく、更新後にすべての変更が失われます)。また、他のスクリプトが破損する可能性があるため、システム全体を変更しないようにしたいと思います。
/bin/sh
グローバルシステムに触れることなく、これらのスクリプトで使用できるbashを指す(一時または非一時)環境を何らかの形で生成する方法はありますか/bin/sh
?
答え1
私は、マウントネームスペースやそれに似たものが何であるかについての異なるアイデアを持って、他のプロセス/ユーザーを予約するために使用できると想像しています/bin/sh
。
しかし、これはハッキングのように聞こえ、「システムを恒久的に変更する」と見なすことができます。 1行の変更を行う方が簡単な場合があります。更新プロセスの修正部分を作成し、バグレポートを公開し、バグのハッシュバンにアップストリームパッチを適用します。
GNU の場合、sed
これを修正するには、次の操作を行う必要があります。
sed -i -e '1s,^#! */bin/sh,#!/bin/bash,' /all/the/scripts/*
答え2
/bin/sh
->が/bin/dash
私のシステムのようにシステム上で動的にリンクされた実行可能ファイルである場合(file(1)を使用して確認できます)、ハッキングを使用してLD_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
したがって、現在実行中のスクリプトや他のシェルは名前を変更しても機能し続け、名前を変更した後はダッシュの代わりにbashを呼び出します。
ただし、システムがスクリプトの編集を許可するように実行されている場合は、スクリプトを編集する方が良いでしょう。
/bin/sh
リンクを に置き換えた場合、bash
タスクが完了したら再/bin/sh
リンクするように変更することを忘れないでください。dash
問題のスクリプトがバイナリパッケージの一部である場合は、問題のアップストリームに関するバグレポートを送信することを忘れないでください。