Sudo를 사용하여 Bash 스크립트 기능 실행


22

여러 가지 다른 작업을 수행하는 스크립트가 있는데 대부분 특별한 권한이 필요하지 않습니다. 그러나 함수 내에 포함 된 하나의 특정 섹션에는 루트 권한이 필요합니다.

전체 스크립트를 루트로 실행하기를 원하지 않고 스크립트 내에서 루트 권한으로이 함수를 호출 할 수 있기를 원합니다. 어쨌든 대부분 대화식이기 때문에 필요한 경우 암호를 묻는 메시지는 문제가되지 않습니다. 그러나을 사용하려고 sudo functionx하면 다음과 같은 결과가 나타납니다.

sudo: functionx: command not found

예상대로 export차이를 만들지 않았습니다. 함수를 여러 가지 이유로 분리하고 별도의 스크립트로 실행하는 대신 스크립트에서 직접 함수를 실행할 수 있기를 원합니다.

함수를 추출하여 적절한 디렉토리를 찾은 다음 독립형 스크립트로 실행하지 않고 기능을 "보이게"할 수있는 방법이 있습니까?

이 함수는 페이지 길이 자체에 관한 것으로, 큰 따옴표와 작은 따옴표로 묶인 여러 문자열을 포함합니다. 또한 메인 스크립트의 다른 곳에 정의 된 메뉴 기능에 의존합니다.

sudo ANY를 가진 사람만이 기능을 실행할 수 있기를 기대합니다. 암호를 변경하는 것 중 하나입니다.


여러 기능이 관련되어 있기 때문에 더욱 복잡하고 실패하기 쉽습니다. 이제 메뉴 기능이 호출 할 수있는 다른 기능과 declare그 와 같은 다른 기능을 포함하여 이러한 모든 종속성 (및 해당되는 경우 여러 수준까지의 모든 종속성)도 찾아야합니다 .
cas

더 나은 대안이 없다면 총알을 깨물고 깨뜨려야합니다 (그리고 실행 경로를 정확하게 결정하고 최종 사용자가 파일을 함께 유지하기를 바랍니다).
BryKKan

답변:


19

나는 이것을하는 간단하고 직관적 인 방법이 없다는 것을 인정할 것이며, 이것은 약간의 해키입니다. 그러나 다음과 같이 할 수 있습니다.

function hello()
{
    echo "Hello!"
}

# Test that it works.
hello

FUNC=$(declare -f hello)
sudo bash -c "$FUNC; hello"

또는 더 간단하게 :

sudo bash -c "$(declare -f hello); hello"

그것은 나를 위해 작동합니다 :

$ bash --version
GNU bash, version 4.3.42(1)-release (x86_64-apple-darwin14.5.0)
$ hello
Hello!
$
$ FUNC=$(declare -f hello)
$ sudo bash -c "$FUNC; hello"
Hello!

기본적으로 declare -f함수의 내용을 반환하고 bash -c인라인으로 전달합니다 .

bash의 외부 인스턴스에서 모든 함수를 내보내려면로 변경 FUNC=$(declare -f hello)하십시오 FUNC=$(declare -f).

편집하다

인용에 대한 주석을 처리하려면 다음 예를 참조하십시오.

$ hello()
> {
> echo "This 'is a' test."
> }
$ declare -f hello
hello ()
{
    echo "This 'is a' test."
}
$ FUNC=$(declare -f hello)
$ sudo bash -c "$FUNC; hello"
Password:
This 'is a' test.

1
이것은 실수로만 작동합니다. 왜냐하면 echo "Hello!"사실상 echo Hello!큰 인용 부호가이 특정 반향 명령에 영향을 미치지 않습니다. 많은 / 대부분의 다른 상황에서, 함수의 큰 따옴표는 bash -c명령 을 어기 게 됩니다.
cas

1
이것은 원래의 질문에 대답하므로 더 나은 해결책을 얻지 못하면 받아 들일 것입니다. 그러나 스크립트의 다른 곳에 정의 된 기능에 의존하기 때문에 특정 기능 (내 편집 참조)이 손상됩니다.
BryKKan

1
나는 오늘 오후 일찍 테스트를했는데 (단순 bash -xc하지 않고 사용 bash -c), bash큰 따옴표를 작은 따옴표로 바꾸고 필요한 경우 변경 '하는 '\''경우 에도이 상황에서 물건을 다시 인용 할만 큼 똑똑한 것처럼 보입니다 . 처리 할 수없는 경우가있을 것 같지만 적어도 간단하고 약간 복잡한 경우에는 확실히 작동합니다 (예 : tryfunction hello() { filename="this is a 'filename' with single quotes and spaces" ; echo "$filename" ; } ; FUNC=$(declare -f hello) ; bash -xc "$FUNC ; hello"
cas

4
@cas declare -f이렇게 재 해석 떠들썩한 파티가 될 수있는 방식으로 함수 정의 프린트 아웃, bash -c "$(declare -f)" 않는 올바르게 작업 (외피는 떠들썩한 파티라고 가정). 따옴표가 변경되었습니다 - 예 당신은 제대로 작동 쇼 게시 추적에를 쉘 구문의 흔적 밖으로 bash는 인쇄, 예를 들어 시도하기 때문에,bash -xc 'echo "hello world"'
질 'SO-정지되는 악'

3
훌륭한 답변입니다. 솔루션을 구현했습니다. 스크립트 내에서 스크립트 자체를 가져올 수 있습니다. 조건부 내에 스크립트가 있으면 sudo yourFunction발견되지
않는지

5

"문제"는 sudo보안 위험으로부터 보호하기 위해 환경 을 지우고 (소수의 허용 변수 제외) 일부 변수를 사전 정의 된 안전 값으로 설정하는 것입니다. 다시 말해, 이것은 실제로 문제가되지 않습니다. 기능입니다.

예를 들어, PATH를 사전 정의 된 값으로 설정 PATH="/path/to/myevildirectory:$PATH"하고 sudo설정하지 않은 경우 전체 경로 이름을 실행하는 모든 명령 (예 : 대부분의 스크립트)으로 전체 경로 이름을 지정하지 않은 스크립트는 /path/to/myevildirectory다른 디렉토리보다 먼저 찾습니다 . 같은 명령을 넣어 ls또는 grep거기에서 다른 일반적인 도구 또는 당신은 쉽게 시스템처럼 당신이 무엇을 할 수 있습니다.

가장 쉬운 방법은 스크립트로 함수를 다시 작성하여 경로의 어딘가에 저장하는 것입니다 (또는 sudo명령 줄 에서 스크립트의 전체 경로를 지정하십시오 - sudo허용 되지 않도록 구성 하지 않은 경우 어쨌든 수행해야 함). 루트로 모든 명령을 실행하고)chmod +x /path/to/scriptname.sh

스크립트는 단지 파일에 함수 정의 내부의 명령을 저장 한 간단 그대로 쉘 기능을 다시 쓰기 (를 빼고 function ..., {}라인).


이것은 어떤 식 으로든 질문에 대답하지 않습니다. 그는 특히 스크립트에 넣지 않기를 원합니다.
Will

1
또한 sudo -E환경을 정리하지 마십시오.
Will

나는 그것이 왜 일어나는지 어느 정도 이해합니다. 이 동작을 일시적으로 무시할 수단이 있기를 바랐습니다. 다른 경우에는 -E 옵션이 언급되었지만이 경우에는 작동하지 않았습니다. 불행히도, 그것을 독립형 스크립트로 만드는 방법에 대한 설명에 감사하지만, 그것을 피할 수있는 수단을 원했기 때문에 특별히 질문에 대답하지 않습니다. 최종 사용자가 스크립트를 배치하는 위치를 제어 할 수 없으며 하드 코드 된 디렉토리와 주 스크립트가 어디서 실행되었는지 정확하게 결정하려는 노래와 춤을 피하고 싶습니다.
BryKKan

그것이 OP가 요구 한 것인지의 여부는 중요하지 않습니다. 그가 원한 것이 효과가 없거나 극도로 안전하지 않은 일을 통해서만 일할 수 있다면 대안을 제시해야합니다. 때로는 그것이 안전하거나 유일하게 최선의 방법입니다). 발로 총을 겨냥하고 방아쇠를 당기면 발생할 수있는 결과에 대해 경고하지 않고 발로 자신을 쏘는 방법을 누군가에게 말하는 것은 무책임한 일입니다.
cas

1
@cas 맞습니다. 어떤 상황에서는 안전하게 할 수없는 대답입니다. 그래도 마지막 편집을 참조하십시오. 보안 관련 사항에 대한 귀하의 의견이 동일한 지 궁금합니다.
BryKKan

3

Sudobash 함수를 작성 하여 함수와 별칭을 호출합니다.

function Sudo {
        local firstArg=$1
        if [ $(type -t $firstArg) = function ]
        then
                shift && command sudo bash -c "$(declare -f $firstArg);$firstArg $*"
        elif [ $(type -t $firstArg) = alias ]
        then
                alias sudo='\sudo '
                eval "sudo $@"
        else
                command sudo "$@"
        fi
}

2

함수와 별칭을 결합 할 수 있습니다

예:

function hello_fn() {
    echo "Hello!" 
}

alias hello='bash -c "$(declare -f hello_fn); hello_fn"' 
alias sudo='sudo '

그런 다음 sudo hello작동


1

다음은 Will의 답변 에 대한 변형입니다 . 추가 cat프로세스가 필요하지만 heredoc의 편의를 제공합니다. 간단히 말해서 다음과 같습니다.

f () 
{
    echo ok;
}

cat <<EOS | sudo bash
$(declare -f f)
f
EOS

더 많은 음식을 원한다면 다음을 시도하십시오.

#!/bin/bash

f () 
{ 
    x="a b"; 
    menu "$x"; 
    y="difficult thing"; 
    echo "a $y to parse"; 
}

menu () 
{
    [ "$1" == "a b" ] && 
    echo "here's the menu"; 
}

cat <<EOS | sudo bash
$(declare -f f)
$(declare -f menu)
f
EOS

출력은 다음과 같습니다.

here's the menu
a difficult thing to pass

여기 우리 menu는 "주 스크립트의 다른 곳에서 정의 된"질문에 해당 하는 기능을 가지고 있습니다. "어딘가"가 기능 요구 sudo가 실행될 때이 단계에서 이미 정의를 읽었 음을 의미 하는 경우 상황은 유사합니다. 그러나 아직 읽지 않았을 수도 있습니다. 정의를 아직 트리거하는 다른 함수가있을 수 있습니다. 이 경우 declare -f menu더 정교한 것으로 대체되거나 전체 스크립트가 menu함수가 이미 선언 된 방식으로 수정되어야합니다 .


매우 흥미로운. 어느 시점에서 시도해야합니다. 그리고 네, menu함수는 f메뉴에서 호출 된 것처럼이 시점 이전에 선언되었을 것 입니다.
BryKKan

0

스크립트가 (a) 자체 포함되어 있거나 (b) 홈 디렉토리의 위치를 ​​기억하지 않고 위치에 따라 구성 요소를 제공 할 수 있다고 가정하면 다음과 같이 할 수 있습니다.

  • 명령의 $0경로 이름을 사용하여 스크립트 의 경로 이름을 사용 sudo하고 스크립트가 확인할 옵션을 전달하여 비밀번호 업데이트를 호출하십시오. 실행하지 않고 경로에서 스크립트를 찾는 ./myscript한에 절대 경로 이름을 가져와야 $0합니다.
  • sudo스크립트 가 실행되므로 스크립트에 필요한 기능에 액세스 할 수 있습니다.
  • 스크립트 상단 (함수 선언을 지나서)에서 스크립트는 스크립트를 검사 uid하여 루트 사용자 로 실행되었음을 인식 하고 비밀번호를 업데이트하고 이동하도록 지시하는 옵션이 설정되어 있는지 확인합니다. 그.

스크립트는 여러 가지 이유로 반복 될 수 있습니다. 권한 변경은 그 중 하나입니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.