異なる/bin/shを使用した環境の分離

異なる/bin/shを使用した環境の分離

/bin/shと同じだと誤って考えるシェルスクリプトがたくさんあります。たとえば、shebangが/bin/bashありますが(ドット)の代わりにコマンドを使用します。#!/bin/shsource.

/bin/shに接続されているUbuntu 16を実行しているため、dashbash-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_PRELOADglibc __libc_start_main(実行ファイルの関数を呼び出す関数)をオーバーライドする小さな動的ライブラリをロードし、main()同じ引数(除く)を使用してargv[0] == /bin/shexecを実行します。それ以外の場合は、何も起こっていないかのようにソースを呼び出します。/bin/bashargv[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/shLD_PRELOADsh_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

問題のスクリプトがバイナリパッケージの一部である場合は、問題のアップストリームに関するバグレポートを送信することを忘れないでください。

関連情報