如何使用sudo执行bash函数?

时间:2012-02-25 23:06:39

标签: bash function sudo

我尝试导出该函数,然后使用bash执行它,但这不起作用:

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

如果我尝试使用没有sudo的bash运行该函数(bash -c'my_func'),它就可以运行。

有什么想法吗?

8 个答案:

答案 0 :(得分:16)

每次运行sudo时,它都会以root用户身份运行并执行shell的新副本。该shell不会从shell继承函数(它不能)并且它不会继承先前执行的函数。你必须写出一个包含函数定义和调用的文件,然后调用它。

答案 1 :(得分:14)

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.   
  3. 用sudo打电话   你好根!
      您通过了以下参数:
      -n
      约翰完成了   -s
      FOO

  4.   



如果你需要在一个shell中使用它来调用你的bashrc中定义的函数,就像另一个用户在serverfault上提出的类似问题一样,那么你必须将之前的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 :(得分:10)

您可以使用declare -f执行此操作,如以下示例所示:

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

myfunc foo
DECL=`declare -f myfunc`

sudo bash -c "$DECL; myfunc bar"

答案 3 :(得分:3)

使用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是否成功的额外点,如果没有则退出该函数。

答案 4 :(得分:1)

对于没有单引号的简短而简单的东西,这对我有用:

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

whoAmI
'
sudo bash -c "$code"

# output: root

答案 5 :(得分:0)

你所要做的就是检查你是否是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

答案 6 :(得分:0)

如果您的函数位于.bashrc中

然后就做 import requests requests.get(url, data=formData)

答案 7 :(得分:0)

我花了几个月的时间来创建这个功能。完全透明,除了添加一个额外的参数外,它与真正的 sudo 命令具有相同的行为:

enter image description here

有必要先创建以下函数:

cmdnames () {
    { printf '%s' "$PATH" | xargs -d: -I{} -- find -L {} -maxdepth 1 -executable -type f -printf '%P\n' 2>/dev/null; compgen -b; } | sort -b | uniq
    return 0
}

完全由我自己创建的函数如下:

sudo () {
    local flagc=1
    local flag=1
    local i
    if [[ $# -eq 1 && ( $1 == "-h" || ( --help == $1* && ${#1} -ge 4 ) ) ]]; then
        command sudo "$@" | perl -lpe '$_ .= "\n  -c, --run-command\t\trun command instead of the function if the names match" if /^  -C, / && ++$i == 1'
        return ${PIPESTATUS[0]}
    fi
    for (( i=1; i<=$#; i++ )); do
        if [[ ${!i} == --r ]]; then
            command sudo "$@" 2>&1 | perl -lpe '$_ .= " '"'"'--run-command'"'"'" if /^sudo: option '"'"'--r'"'"' is ambiguous/ && ++$i == 1'
            return ${PIPESTATUS[0]}
        fi
        if [[ ${!i} == -c || ( --run-command == ${!i}* && $(expr length "${!i}") -ge 4 ) ]]; then
            flag=2
            set -- "${@:1:i-1}" "${@:i+1}"
            i=$((i-1))
            continue
        fi
        command sudo 2>&1 | grep -E -- "\[${!i} [A-Za-z]+\]" > /dev/null && { i=$((i+1)); continue; }
        cmdnames | grep "^${!i}$" > /dev/null && flagc=0
        if [[ $flagc -eq 0 && $flag -eq 2 ]]; then break; fi
        if declare -f -- "${!i}" &> /dev/null; then
            flag=0
            break
        else
            if [[ $flagc -eq 0 ]]; then break; fi
        fi
    done
    if [[ $flag -eq 0 ]]; then
        command sudo "${@:1:i-1}" bash -sc "shopt -s expand_aliases extglob; $(alias); $(declare -f); $(printf "%q " "${@:i}")"
    else
        command sudo "$@"
    fi
    return $?
}

缺点:无。