web-dev-qa-db-ja.com

sudoを使用してbash関数を実行するにはどうすればよいですか?

関数をエクスポートしてからbashで実行しようとしましたが、機能しません。

$ export -f my_func
$ Sudo bash -c 'my_func' 
bash: my_func: command not found

Sudoを使用せずにbashを使用して関数を実行しようとすると(bash -c'my_func ')、機能します。

何か案が?

24
Miroslav

bmargulies の答えから始めて、この問題をカバーする関数を作成しました。これは基本的に彼のアイデアを実現します。

# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #
# EXESUDO
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #
#
# Purpose:
# -------------------------------------------------------------------- #
# Execute a function with Sudo
#
# Params:
# -------------------------------------------------------------------- #
# $1:   string: name of the function to be executed with Sudo
#
# Usage:
# -------------------------------------------------------------------- #
# exesudo "funcname" followed by any param
#
# -------------------------------------------------------------------- #
# Created 01 September 2012              Last Modified 02 September 2012

function exesudo ()
{
    ### ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ##
    #
    # LOCAL VARIABLES:
    #
    ### ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ##

    #
    # I use underscores to remember it's been passed
    local _funcname_="$1"

    local params=( "$@" )               ## array containing all params passed here
    local tmpfile="/dev/shm/$RANDOM"    ## temporary file
    local content                       ## content of the temporary file
    local regex                         ## regular expression


    ### ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ##
    #
    # MAIN CODE:
    #
    ### ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ##

    #
    # WORKING ON PARAMS:
    # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    #
    # Shift the first param (which is the name of the function)
    unset params[0]              ## remove first element
    # params=( "${params[@]}" )     ## repack array


    #
    # WORKING ON THE TEMPORARY FILE:
    # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    content="#!/bin/bash\n\n"

    #
    # Write the params array
    content="${content}params=(\n"

    regex="\s+"
    for param in "${params[@]}"
    do
        if [[ "$param" =~ $regex ]]
            then
                content="${content}\t\"${param}\"\n"
            else
                content="${content}\t${param}\n"
        fi
    done

    content="$content)\n"
    echo -e "$content" > "$tmpfile"

    #
    # Append the function source
    echo "#$( type "$_funcname_" )" >> "$tmpfile"

    #
    # Append the call to the function
    echo -e "\n$_funcname_ \"\${params[@]}\"\n" >> "$tmpfile"


    #
    # DONE: EXECUTE THE TEMPORARY FILE WITH Sudo
    # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    Sudo bash "$tmpfile"
    rm "$tmpfile"
}



使用例:
次のスニペットを実行する

#!/bin/bash

function exesudo ()
{
    # copy here the previous exesudo function !!!
}

test_it_out ()
{
    local params=( "$@" )
    echo "Hello "$( whoami )"!"
    echo "You passed the following params:"
    printf "%s\n" "${params[@]}" ## print array
}

echo "1. calling without Sudo"
test_it_out "first" "second"

echo ""
echo "2. calling with Sudo"
exesudo test_it_out -n "john done" -s "done"

exit



出力されます

  1. 須藤なしで呼び出す
    君の名は。
    次のパラメータを渡しました:
    最初

  2. 須藤との通話
    こんにちはルート!
    次のパラメータを渡しました:
    -n
    ジョン・ダン
    -s
    foo



bashrcで定義されている関数を呼び出すシェルでこれを使用する必要がある場合は、別のユーザーから serverfault で同様の質問があり、前のユーザーを配置する必要があります。次のように、同じbashrcファイルのexesudo関数も同様です。

function yourfunc ()
{
echo "Hello "$( whoami )"!"
}
export -f yourfunc

function exesudo ()
{
   # copy here
}
export -f exesudo



次に、ログアウトして再度ログインするか、を使用する必要があります

source ~/.bashrc



最後に、次のようにexesudoを使用できます。

$ yourfunc
Hello yourname!

$ exesudo yourfunc
Hello root!
15
Luca Borrione

Sudoを実行するたびに、rootとして実行されているシェルの新しいコピーをフォークして実行します。そのシェルはシェルから関数を継承せず(継承できません)、以前の実行から関数を継承しません。関数の定義と呼び出し、およびその呼び出しを含むファイルを書き出す必要があります。

17
bmargulies

次の例のように、declare -fを使用してこれを行うことができます。

function myfunc() {
    whoami
    echo First parameter is $1
}

myfunc foo
DECL=`declare -f myfunc`

Sudo bash -c "$DECL; myfunc bar"
10
Karatheodory

Sudoを使用して関数を呼び出す代わりに、関数内で「Sudo」呼び出しを移動することもできます。たとえば、ローカルホストを特定のポートに転送するためのショートカット機能をOSXに設定したいと考えていました。

function portforward() {
    echo "y" | Sudo ipfw flush;
    Sudo ipfw add 100 fwd 127.0.0.1,$1 tcp from any to any 80 in;
    echo "Forwarding localhost to port $1!";
}

この関数はSudoをヒットし、パスワードを要求します。 (次に、この質問とは関係なく、「y」をipfwのプロンプトにパイプします)。その後、Sudoがキャッシュされるため、残りの関数はパスワードを入力しなくても実行されます。

基本的に、これは次のように実行されます。

portforward 8000
Password:
Forwarding localhost to port 8000!

また、パスワードを入力する必要があるのは1回だけで、パスワードが処理されるため、ニーズが満たされます。初めてパスワードを入力しなかった場合は少し醜いですが。最初のSudoが成功したかどうかを検出し、成功しなかった場合は関数を終了するための追加のポイント。

3
timothyashaw

一重引用符が含まれていない短くて単純なものの場合、これは私にとってはうまくいきます:

export code='
function whoAmI() {
    echo `whoami`
}

whoAmI
'
Sudo bash -c "$code"

# output: root
1
Shavais

関数が.bashrcにある場合

次に、Sudo -i myfunc

0
Josh

あなたがしなければならないのはあなたがrootであるかどうかをチェックすることです、もしそうなら、関数を実行します、そうでなければ、Sudoでスクリプトを呼び出します:

#!/bin/bash
# script name: 'foo.sh'

function foo(){
    whoami
}

DIR=$( cd "$( dirname "$0" )" && pwd )   # get script dir
if [ "$UID" -ne 0 ]; then                # check if you are root
    Sudo $DIR/foo.sh                     # NOT: run script with Sudo
else
    foo                                  # YES: run function
fi
0
gospes