Как я могу выполнить функцию bash, используя sudo? - PullRequest
24 голосов
/ 26 февраля 2012

Я попытался экспортировать функцию и затем выполнить ее с помощью bash, но это не сработало:

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

Если я попытаюсь запустить функцию с bash без sudo (bash -c 'my_func'), это сработает.

Есть идеи?

Ответы [ 7 ]

16 голосов
/ 26 февраля 2012

Каждый раз, когда вы запускаете sudo, он создает и запускает новую копию оболочки, работающую от имени пользователя root. Эта оболочка не наследует функции от вашей оболочки (она не может) и не наследует функции от предыдущих выполнений. Вам нужно будет записать файл, содержащий определение и вызов функции, и sudo вызов этого.

14 голосов
/ 01 сентября 2012

Начиная с ответа 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, как это было задано с аналогичным вопросом о serverfault другим пользователем, то вы должны поместить предыдущую функцию exesudo в ту же * Файл 1046 * 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!
10 голосов
/ 25 сентября 2013

Вы можете сделать это, используя declare -f, как в следующем примере:

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

myfunc foo
DECL=`declare -f myfunc`

sudo bash -c "$DECL; myfunc bar"
3 голосов
/ 24 октября 2013

Альтернативой вызову вашей функции с помощью sudo является просто перемещение вызовов "sudo" внутри вашей функции.Например, я хотел настроить функцию ярлыка в OS X для пересылки localhost на определенный порт.

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!

И удовлетворяет мою потребность, потому что я толькоНужно ввести пароль один раз, и он позаботится о.Хотя это немного уродливо, если вы не можете ввести пароль с первого раза.Дополнительные баллы для определения, успешно ли прошел первый sudo, и выхода из функции, если нет.

1 голос
/ 12 апреля 2013

Для коротких и простых вещей, в которых нет одинарных кавычек, это работает для меня:

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

whoAmI
'
sudo bash -c "$code"

# output: root
0 голосов
/ 10 июня 2019

Если ваша функция в вашем .bashrc

, тогда просто сделайте sudo -i myfunc

0 голосов
/ 14 марта 2014

Все, что вам нужно сделать, это проверить, являетесь ли вы пользователем 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
...