sudo로 bash 함수를 어떻게 실행할 수 있습니까?


29

글로벌 bashrc에 bash 함수가 정의되어 있으며 루트 권한이 필요합니다. 예를 들어 sudo로 어떻게 실행할 수 있습니까 sudo myfunction? 기본적으로 오류가 발생합니다.

sudo : myfunction : 명령을 찾을 수 없습니다


2
시도하지는 않았지만이 블로그 게시물에서 처리하는 것 같습니다 : w00tbl0g.blogspot.com/2007/05/…
Grizly

위 스크립트를 설치하려면 imho 권장하지 않는 'set alias sudo = sudowrap'이 필요합니다. 작동하지 않는 솔루션에 대한 답변을 참조하십시오.
Luca Borrione

이것은 쉘 기능이 악한 많은 이유 중 하나입니다. 쉘 기능은 환경을 변경하려는 명령으로 제한되어야합니다. 나머지는 실제 스크립트를 사용하십시오. 기능의 장점은 무엇입니까? (좋아요, "과용"은 기능 자체가 아니라 악입니다. 그리고 다른 많은 좋은 이유가있을 것입니다. 그러나 스크립트를 작성할 때 규칙이 아니라 예외가되어야합니다.)
Jeff Learman

답변:


4

Luca는 친절 하게이 질문에 나를 지적했습니다. 여기의 접근 방식은 다음과 같습니다. sudo를 호출하기 전에 함수 / 별칭을 확장하고 임시 파일이 필요하지 않고 sudo로 전체 전달하십시오.

여기 내 블로그에 설명되어 있습니다 . 견적 처리가 많이 있습니다 :-)

# Wrap sudo to handle aliases and functions
# Wout.Mertens@gmail.com
#
# 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

이 접근 방식의 한 가지 단점은 호출하는 함수 만 확장한다는 것입니다. 여기에서 참조하는 추가 함수는 아닙니다. Kyle의 접근 방식은 bashrc에로드 된 함수를 참조하면 더 잘 처리 할 수 ​​있습니다 ( bash -c통화에서 실행되는 경우 ).


ServerFault에서는 원하는 코드를 표시하고 외부 사이트에 연결하는 것이 좋으므로 사용자가 원하는 정보를 얻기 위해 클릭하지 않아도되므로 정보는 외부 사이트의 잠재적 인 죽음에서 살아남을 수 있습니다.
눈에 띄는 컴파일러

15

서브 쉘이나이를 사용하려는 스크립트에서 export사용할 수 있도록 기능을 수행 할 수 있습니다 bash -c.

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

편집하다

이것은 직접 서브 쉘에서 작동하지만 분명히 sudo함수를 전달하지는 않습니다 (변수 만). 심지어의 다양한 조합을 사용하여 setenv, env_keep그리고 부정 env_reset도움말을하지 않는 것.

편집 2

그러나 , 그 표시 su 하지 지원 수출 기능을.

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

2
+1, 나는 이것이 정답이라고 말할 것입니다.
Kyle Brandt

1
이 방법이 작동하는지 여부 ?? 제 경우에는 그렇지 않습니다.
pradeepchhetri

@pradeepchhetri 정확히 무엇을 시도하고 있는지, 어떤 쉘을 사용하고 어떤 OS를 사용하는지와 같은 더 많은 정보를 제공 할 수 있습니다.
Legolas

@ Legolas : 위의 스크립트에서 작성한 것과 동일한 것을 시도하고 있습니다. 오류가 발생했습니다 bash: your_function: command not found. 그리고를 사용 Ubuntu 11.04하고 bash shell있습니다.
pradeepchhetri

@pradeepchhetri 만약 사용한다면 sudo -E bash -c 'your_function'?
Legolas

4

어쩌면 당신은 할 수 있습니다 :

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

이렇게하면 명령 줄에 sudo를 입력하지 않아도됩니다.


1
시스템에 따라 ... 이것은 sudo 명령을 호출 할 때마다 암호를 입력하라는 메시지를 표시하거나 ... 한 번 묻고 캐시합니다. 루트로 실행 중인지 감지하는 것이 좋으며 그렇지 않은 경우 sudo로 bash 스크립트를 다시 호출하십시오.
TheCompWiz

sudo 비밀번호를 캐시하지 않는 시스템이 아직 발생하지 않았습니다. timestamp_timeout의 기본값은 5입니다. 0으로 설정하면 항상 비밀번호를 요청하지만 사용자 정의 설정이됩니다.
wzzrd

3

sudo 컨텍스트에서 함수를 호출해야하는 경우 다음을 사용하려고합니다 declare.

#!/bin/bash

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

sudo su another_user -c "$(declare -f hello); hello"

함수가 다른 함수를 호출하지 않는 한 작동합니다.
modiX

내 유스 케이스의 경우 이것이 가장 좋은 대답입니다.
Jim

2

sudo가 쉘 자체를 실행하도록하여 새로운 쉘을 실행하면 함수는 루트 권한으로 실행됩니다. 예를 들면 다음과 같습니다.

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

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

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

2

Dennis Williamson 의 답변에 대한 의견에서 Legolas가 지적한 것처럼 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없이 전화
    하세요 안녕하세요 yourname!
    다음 매개 변수를 통과했습니다.

    번째 초

  2. sudo
    Hello root로 전화 !
    다음 매개 변수를 전달했습니다.
    -n
    john done
    -s
    foo



요청 한대로 bashrc에 정의 된 함수를 호출하는 쉘에서 이것을 사용해야하는 경우 다음과 같이 동일한 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!

를 반환합니다 /dev/shm/22481: No such file or directory.
modiX
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.