web-dev-qa-db-ja.com

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

グローバルbashrcで定義されたbash関数があり、動作するにはroot権限が必要です。どうすればSudoで実行できますか? Sudo myfunction。デフォルトではエラーが発生します。

Sudo:myfunction:コマンドが見つかりません

29
Eugene Yarmash

Lucaがこの質問に親切に指摘してくれました。これが私のアプローチです。Sudoを呼び出す前に関数/エイリアスを展開し、その全体をSudoに渡します。一時ファイルは必要ありません。

説明 ここに私のブログ 。相場の取り扱いはたくさんあります:-)

# Wrap Sudo to handle aliases and functions
# [email protected]
#
# Accepts -x as well as regular Sudo options: this expands variables as you not root
#
# Comments and improvements welcome
#
# Installing: source this from your .bashrc and set alias Sudo=sudowrap
#  You can also wrap it in a script that changes your terminal color, like so:
#  function setclr() {
#   local t=0               
#   SetTerminalStyle $1                
#   shift
#   "$@"
#   t=$?
#   SetTerminalStyle default
#   return $t
#  }
#  alias Sudo="setclr Sudo sudowrap"
#  If SetTerminalStyle is a program that interfaces with your terminal to set its
#  color.

# Note: This script only handles one layer of aliases/functions.

# If you prefer to call this function Sudo, uncomment the following
# line which will make sure it can be called that
#typeset -f Sudo >/dev/null && unset Sudo

sudowrap () 
{
    local c="" t="" parse=""
    local -a opt
    #parse Sudo args
    OPTIND=1
    i=0
    while getopts xVhlLvkKsHPSb:p:c:a:u: t; do
        if [ "$t" = x ]; then
            parse=true
        else
            opt[$i]="-$t"
            let i++
            if [ "$OPTARG" ]; then
                opt[$i]="$OPTARG"
                let i++
            fi
        fi
    done
    shift $(( $OPTIND - 1 ))
    if [ $# -ge 1 ]; then
        c="$1";
        shift;
        case $(type -t "$c") in 
        "")
            echo No such command "$c"
            return 127
            ;;
        alias)
            c="$(type "$c")"
            # Strip "... is aliased to `...'"
            c="${c#*\`}"
            c="${c%\'}"
            ;;
        function)
            c="$(type "$c")"
            # Strip first line
            c="${c#* is a function}"
            c="$c;\"$c\""
            ;;
        *)
            c="\"$c\""
            ;;
        esac
        if [ -n "$parse" ]; then
            # Quote the rest once, so it gets processed by bash.
            # Done this way so variables can get expanded.
            while [ -n "$1" ]; do
                c="$c \"$1\""
                shift
            done
        else
            # Otherwise, quote the arguments. The echo gets an extra
            # space to prevent echo from parsing arguments like -n
            while [ -n "$1" ]; do
                t="${1//\'/\'\\\'\'}"
                c="$c '$t'"
                shift
            done
        fi
        echo Sudo "${opt[@]}" -- bash -xvc \""$c"\" >&2
        command Sudo "${opt[@]}" bash -xvc "$c"
    else
        echo Sudo "${opt[@]}" >&2
        command Sudo "${opt[@]}"
    fi
}
# Allow sudowrap to be used in subshells
export -f sudowrap

このアプローチの欠点の1つは、呼び出す関数を拡張するだけで、そこから参照している追加の関数は拡張しないことです。 Kyleのアプローチは、bashrcにロードされている関数を参照している場合に、より適切に処理されます(bash -c呼び出しで実行される場合)。

4
w00t

関数をexportして、使用したいbash -cサブシェルまたはスクリプトで使用できるようにすることができます。

your_function () { echo 'Hello, World'; }
export -f your_function
bash -c 'your_function'

編集

これは直接サブシェルで機能しますが、Sudoは関数を転送しません(変数のみ)。 setenvenv_keepのさまざまな組み合わせを使用してenv_resetを否定しても効果がないようです。

編集2

ただしsudoesはエクスポートされた関数をサポートしているようです。

your_function () { echo 'Hello, World'; }
export -f your_function
su -c 'your_function'

たぶんあなたができる:

function meh() {
    Sudo -v
    Sudo cat /etc/shadow
}

これは機能するはずであり、コマンドラインでSudoを入力する手間が省けます。

4
wzzrd

Sudoのコンテキストで関数を呼び出す必要がある場合は、declareを使用します。

#!/bin/bash

function hello() {
  echo "Hello, $USER"
}

Sudo su another_user -c "$(declare -f hello); hello"
4
ferdy

私はSudoにシェル自体を実行させることによって新しいシェルを実行し、関数はroot権限で実行されます。たとえば次のようなもの:

vim myFunction
#The following three lines go in myFunction file
function mywho {
    Sudo whoami
}

Sudo bash -c '. /home/kbrandt/myFunction; mywho'
root

次に、Sudo bash行のエイリアスを作成することもできます。

2
Kyle Brandt

Legolasが Dennis Williamson の回答のコメントで指摘したように、stackoverflowに投稿された同様の質問で bmargulies の回答を読む必要があります。

そこから、私はこの問題をカバーする関数を書きました。これは基本的に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 filecontent                   ## content of the temporary file
    local regex                         ## regular expression
    local func                          ## function source


    ### ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ##
    #
    # 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. sudoなしで呼び出す
    こんにちは、あなたの名前です!
    次のパラメータを渡しました:
    最初

  2. sudoで呼び出す
    こんにちは!
    次のパラメータを渡しました:
    -n
    ジョン完了
    -s
    foo



あなたが尋ねたように、bashrcで定義された関数を呼び出すシェルでこれを使用する必要がある場合、前のexesudo関数を同じbashrcに置く必要がありますファイルも次のようになります。

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!
2
Luca Borrione
#!/bin/bash

function smth() {
    echo "{{"
    whoami
    echo "}}"
}

if [ $(whoami) != "root" ]; then
    whoami
    echo "i'm not root"
    Sudo $0
else
    smth
fi
2
burz