web-dev-qa-db-ja.com

Sudoを使用してBashスクリプト関数を実行する

私はさまざまなことを行うスクリプトを持っていますが、そのほとんどは特別な特権を必要としません。ただし、関数内に含まれている特定のセクションには、root権限が必要です。

スクリプト全体をrootとして実行する必要はなく、スクリプト内からroot権限でこの関数を呼び出すことができます。とにかくほとんどインタラクティブなので、必要に応じてパスワードを要求することは問題ではありません。しかし、Sudo functionxを使用しようとすると、次のようになります。

Sudo: functionx: command not found

予想通り、exportは違いをもたらしませんでした。いくつかの理由により、関数を分割して別のスクリプトとして実行するのではなく、スクリプト内で直接関数を実行できるようにしたいと考えています。

関数を抽出して適切なディレクトリを見つけ、それをスタンドアロンスクリプトとして実行せずに、関数をSudoに「可視」にする方法はありますか?

この関数はページ自体が長く、複数の文字列が含まれています。また、メインスクリプトの他の場所で定義されているメニュー関数にも依存しています。

パスワードを変更することの1つであるため、Sudo ANYを持つ誰かが関数を実行できることを期待します。

25
BryKKan

これを行う簡単で直感的な方法はないことを認めます。これは少し厄介です。しかし、あなたはこのようにそれを行うことができます:

_function hello()
{
    echo "Hello!"
}

# Test that it works.
hello

FUNC=$(declare -f hello)
Sudo bash -c "$FUNC; hello"
_

またはもっと簡単に:

_Sudo bash -c "$(declare -f hello); hello"
_

わたしにはできる:

_$ bash --version
GNU bash, version 4.3.42(1)-release (x86_64-Apple-darwin14.5.0)
$ hello
Hello!
$
$ FUNC=$(declare -f hello)
$ Sudo bash -c "$FUNC; hello"
Hello!
_

基本的に、_declare -f_は関数の内容を返し、_bash -c_にインラインで渡します。

すべての関数をbashの外部インスタンスからエクスポートする場合は、FUNC=$(declare -f hello)FUNC=$(declare -f)に変更します。

編集

引用に関するコメントに対処するには、次の例を参照してください。

_$ hello()
> {
> echo "This 'is a' test."
> }
$ declare -f hello
hello ()
{
    echo "This 'is a' test."
}
$ FUNC=$(declare -f hello)
$ Sudo bash -c "$FUNC; hello"
Password:
This 'is a' test.
_
20
Will

「問題」とは、Sudoが環境をクリアし(許可された少数の変数を除く)、セキュリティリスクから保護するために、いくつかの変数を事前定義された安全な値に設定することです。つまり、これは実際には問題ではありません。それが特徴です。

たとえば、PATH="/path/to/myevildirectory:$PATH"を設定し、SudoがPATHを事前定義された値に設定しなかった場合、実行するすべてのコマンド(つまり、ほとんどのスクリプト)への完全パス名を指定しなかったスクリプト他のディレクトリの前に/path/to/myevildirectoryを探します。 lsgrepのようなコマンド、またはその他の一般的なツールをそこに置くと、システムで好きなことを簡単に実行できます。

最も簡単で最善の方法は、関数をスクリプトとして書き直してパスのどこかに保存する(またはSudoコマンドラインでスクリプトへのフルパスを指定する)です。これはとにかく行う必要があります。 Sudoがrootとして任意のコマンドを実行できるように構成されていない限り)、chmod +x /path/to/scriptname.shで実行可能にします

シェル関数をスクリプトとして書き換えるのは、関数定義内のコマンドをファイルに保存するのと同じくらい簡単です(function ...{}行なしで)。

5
cas

私はそれを行うために自分のSudo bash関数を書きました、それは関数とエイリアスを呼び出すように機能します:

function Sudo {
        local firstArg=$1
        if [ $(type -t $firstArg) = function ]
        then
                shift && command Sudo bash -c "$(declare -f $firstArg);$firstArg $*"
        Elif [ $(type -t $firstArg) = alias ]
        then
                alias Sudo='\Sudo '
                eval "Sudo $@"
        else
                command Sudo "$@"
        fi
}
3
SebMa

関数とエイリアスを組み合わせることができます

例:

function hello_fn() {
    echo "Hello!" 
}

alias hello='bash -c "$(declare -f hello_fn); hello_fn"' 
alias Sudo='Sudo '

次にSudo hello機能

2
hbt

Will's answer のバリエーションを以下に示します。追加のcatプロセスが必要ですが、ヒアドキュメントの快適さを提供します。一言で言えば、それはこのようになります:

f () 
{
    echo ok;
}

cat <<EOS | Sudo bash
$(declare -f f)
f
EOS

あなたがより多くの食べ物を考えたいなら、これを試してください:

#!/bin/bash

f () 
{ 
    x="a b"; 
    menu "$x"; 
    y="difficult thing"; 
    echo "a $y to parse"; 
}

menu () 
{
    [ "$1" == "a b" ] && 
    echo "here's the menu"; 
}

cat <<EOS | Sudo bash
$(declare -f f)
$(declare -f menu)
f
EOS

出力は次のとおりです。

here's the menu
a difficult thing to pass

ここでは、「メインスクリプトの別の場所で定義されている」問題の関数に対応するmenu関数があります。 「他の場所」は、Sudoを要求する関数が実行されているこの段階でその定義がすでに読み取られていることを意味する場合、状況は類似しています。しかし、それはまだ読まれていないかもしれません。その定義をトリガーする別の関数があるかもしれません。この場合 declare -f menuをより洗練されたものに置き換えるか、menu関数がすでに宣言されている方法でスクリプト全体を修正する必要があります。

1
user147505

スクリプトが(a)自己完結型であるか、または(b)(ホームディレクトリの場所を覚えているのではなく)場所に基づいてコンポーネントを調達できると仮定すると、次のようなことができます。

  • スクリプトの$0パス名をSudoコマンドで使用し、スクリプトがチェックするオプションを渡して、パスワードの更新を呼び出します。 (./myscriptを実行するだけでなく)パスでスクリプトを見つけることに依存している限り、$0で絶対パス名を取得する必要があります。
  • Sudoはスクリプトを実行するため、スクリプトで必要な関数にaccessが含まれています。
  • スクリプトの上部で(むしろ関数宣言を過ぎて)、スクリプトはuidをチェックし、rootユーザーとして実行されたことを認識し、オプションを設定してパスワードを更新するように指示し、実行します。

スクリプトはさまざまな理由で繰り返し発生する可能性があります。特権の変更もその1つです。

0
Thomas Dickey