줄 시작 부분에 "sudo"를 입력하면 나머지 명령에도 적용됩니까?

줄 시작 부분에 "sudo"를 입력하면 나머지 명령에도 적용됩니까?

Bash에서 줄 시작 부분에 입력 하면 sudo나머지 명령에도 적용됩니까?

즉, 이는 다음과 같습니다.

sudo foo | foo2 | foo3

이것과 동등합니다:

sudo foo | sudo foo2 | sudo foo3

답변1

제공된 첫 번째 명령으로만 실행하고 첫 번째 파이프 이후의 다른 모든 항목은 원래 사용자 ID로 실행된다는 것을 스스로 확신하는 방법으로 sudo이 쓸모 없는 명령 체인을 사용하여 이를 확인할 수 있습니다.

예시 #1

$ sudo whoami > file1 | whoami > file2 | whoami > file3

그런 다음 이 파일을 보면 cat다음과 같은 사용자 이름이 표시됩니다.

$ cat file{1..3}
root
saml
saml

예시 #2

그러나 서브셸을 실행하는 경우:

$ sudo sh -c 'whoami > file4 | whoami > file5 | whoami > file6'

그런 다음 이 파일을 보면 cat다음과 같은 사용자 이름이 표시됩니다.

$ cat file{4..6}
root
root
root

예시 #3

sudo foo1 | sudo foo2 ...의 출력이 sudo foo1에 제공되기 때문에 귀하의 의견은 작동하지 않습니다 sudo foo2. 내 whoami예를 사용하면 명령 체인이 아무 작업도 수행하지 않음을 알 수 있습니다.

$ sudo whoami | sudo whoami | sudo whoami
root

첫 번째는 실행됐지만, 두 번째와 세 번째는 입력을 받아들이는 능력이 없어 아무것도 하지 못했다. 대신에 다음과 같이 작성하려고 한다고 생각합니다.

$ sudo whoami;sudo whoami;sudo whoami
root
root
root

이는 3개의 다른 명령 프롬프트에서 3번 실행하는 것과 같습니다. 아니면 이거:

$ sudo whoami && sudo whoami && sudo whoami
root
root
root

하지만 마지막 것은 절대 하지 마세요. 다음 섹션에 속합니다.

sudo를 호출하는 모호한 방법

이것이 최선의 노력은 아니지만 여러 명령을 실행하는 데 사용하는 다른 방법을 볼 수 있습니다 sudo. 난 그들에게 여기를 보여주려고가르치다필연적으로 다른 사람을 허용하지 마십시오하다그들을!

방법 1

$ echo "echo 1 > /proc/sys/vm/drop_caches" | sudo sh

어떻게 작동하나요?

sudo 때문에 큰따옴표 안의 echo 프로그램은 루트로 실행되지만, echo의 출력을 루트 전용 파일로 리디렉션하는 셸은 여전히 ​​사용자로 실행됩니다. 현재 쉘은 시작하기 전에 리디렉션을 수행합니다 sudo.

방법 #2

$ sudo tee /proc/sys/vm/drop_caches <<<1

어떻게 작동하나요?

이 방법은 tee프로그램을 루트로 실행하고여기에 있는 문자열sudo명령을 호출하기 전에 실행됩니다 tee.

방법 #3

# this way
$ sudo -s -- 'whoami'

# or this way
sudo -s -- sh -c 'whoami;whoami'

어떻게 작동하나요?

다르게 보일 수도 있지만 실제로는 같은 일을 하고 있습니다. -s스위치를 사용 하면 sudo단일 명령이 실행됩니다. 탈출구가 있는지 전혀 모르겠습니다. 이와 같은 것은 작동하지 않습니다.

# this
$ sudo -s -- 'whoami;whoami'

# or this
$ sudo -s -- 'whoami\;whoami'

그러나 매뉴얼 페이지를 보면 -s스위치는 사용자 파일 항목에 정의된 쉘에 단일 명령을 전달한다고 나와 있습니다 /etc/passwd. 따라서 sh -c우리는 실행될 명령 문자열을 "백도어"하는 또 다른 쉘( )인 쉘을 전달하는 것과 관련된 두 번째 형태의 트릭을 사용합니다 .

더 많은 것이 있지만 여기서 멈추겠습니다. 이것은 단지 당신이 이해하고 있다면 무엇을 할 수 있는지 보여주기 위한 것입니다. 하지만 반드시 쓰레기를 서로 연결할 필요는 없습니다. 다른 사람들이 이해하고 지원할 수 있도록 코드 프라그마를 논리적인 수준으로 유지해야 합니다. 미래에 있습니다.

답변2

아니요, 귀하의 예 foo에서는 sudo. 높은 권한으로 모든 명령을 실행하려면 셸을 생성할 수 있습니다.

sudo sh -c 'foo | foo2 | foo3'

답변3

아니, 그런데 왜요?

아니요, sudo나머지 파이프라인에는 해당되지 않습니다.이 다른 답변몇 가지 예가 제시되어 있지만 그 뒤에 숨어 있는 메커니즘을 모두 설명하지는 않습니다.

결론은 sudo실행하는 쉘에 관계없이 단일 실행 파일입니다. 문제의 명령은 다음과 같습니다.

sudo foo | foo2 | foo3

쉘의 경우에도 마찬가지입니다 cat foo | foo2 | foo3. 쉘은 세 부분으로 구성된 파이프를 인식하고 시작 sudo하기 cat전에 파이프를 설정합니다 . 쉘은 이것이 foo궁극적으로 명령이 될 것이라는 것을 전혀 모릅니다 . shell은 foo단지 인자이므로 에 전달해야 합니다 sudo.

위의 경우 다음 두 가지 경우 중 어느 것도 발생하지 않지만 , , 을 매개 변수로 취 sudo하거나 하나의 매개변수로 전달 하더라도 쉘 구문에 속하기 때문에 어쨌든 전체 명령이 예상대로 작동하지 않습니다. , 기본적으로 쉘이 작동하지도 않고 쉘이 실행되지도 않습니다.foo|foo2|foo3foo | foo2 | foo3|sudo


sudo다음을 사용하여 여러 명령을 실행하는 두 가지 방법:

해석하려면 쉘이 필요합니다 |. 이는 두 가지 기본 접근 방식으로 이어집니다.

  1. sudo foo | sudo foo2 | sudo foo3메인 하우징 처리 배관;
  2. sudo sh -c 'foo | foo2 | foo3'새로운 높은 인클로저가 덕트를 처리합니다.

와 유사 &&및/또는 ||대체 또는 유사합니다 |.

사례 2에서는 기본 쉘이 시작되고 sudowhile은 foo | foo2 | foo3인수 중 하나일 뿐이며, 이는 무엇이든 문자열일 수 있으며 sudo나중에 시작하여 인수로 전달합니다 sh. foo | foo2 | foo3내부 문자열만 sh쉘 코드로 해석됩니다.

내가 작성했지만 sh -c다른 쉘을 사용할 수 있습니다. 이는 일반이 지원하지 않는 기능이 필요한 경우 특히 적합합니다 sh.


현명한 선택을 해라

일반적으로 저는 쉘을 부착한 방법(방법 2)을 선호합니다. 내 이유는 다음과 같습니다.

  • 하나만 있으며 sudo최대 한 번 자격 증명을 요청합니다. 의 경우 sudo … | sudo …구성( sudoers)에 따라 각각 sudo개별적으로 요청될 수 있습니다. 이 도구는 동일한 터미널을 사용하는 여러 인스턴스가 서로 간섭하지 않고 셸이 병렬로 실행하더라도 순차적으로 요청되도록 충분히 똑똑합니다. 더 나쁜 경우, sudo … && sudo …일반적으로 두 번째는 sudo(조건부로) 몇 시간 후에 시작될 수 있으므로 sudo두 번째는 비밀번호를 너무 자주 묻지 않도록 구성한 경우에도 물을 수 sudo있으며 이러한 일이 언제 발생하는지 예측하지 못할 수 있습니다.

  • 리디렉션이 포함된 경우에는 필요하지 않습니다.속임수와tee(입력 리디렉션을 대체하지도 않습니다 sudo cat … | …). 상승된 쉘이 리디렉션을 처리하도록 하면 가장 자연스러운 방법으로 문제가 해결됩니다. 이는 실제로 일부 파일을 루트로 열고 싶다고 가정합니다.

반면에 방법 2에도 단점이 있습니다. 어떤 경우에는 방법 1을 선택할 수도 있습니다. 고려해야 할 사항:

  • sudo some_shell -c …새로운 상승된 some_shell. 버그가 있을 수도 있고 some_shell, 전달한 셸 코드에 버그가 있을 수도 있습니다. 버그로 인해 셸이 예상치 못한 작업을 수행할 수도 있습니다. 승격된 프로세스가 예상치 못한 작업을 수행하게 하는 것은 매우 나쁜 일입니다. 따라서 foo, foo2및 을 높이고 싶을 수도 있지만 foo3그게 전부입니다.

  • 전달된 셸 코드는 sh -c단일 인수여야 합니다. 거의 모든 경우(확실히 귀하의 경우) 공백 및 기타 문자를 인용하거나 이스케이프 처리해야 합니다. 추가적인 수준의 인용/이스케이프는 복잡성을 더합니다. 일반적으로 이미 인용되었거나 이스케이프된 항목을 적절하게 인용/이스케이프하는 방법을 알아야 합니다.

    잠재적으로 도움이 될 수 있는 리소스:Bash에서 작은따옴표를 편리하게 사용하거나 전체 명령줄을 이스케이프하는 방법은 무엇입니까?

  • 에 의해 시작된 쉘은 sudo메인 쉘의 변수에 접근할 수 없습니다. 변수 내보내기는 도움이 될 수도 있고 그렇지 않을 수도 있습니다. sudo환경에서 변수를 제거하도록 구성할 수 있습니다. 메인 쉘에서 확장한 변수를 다른 쉘의 코드에 삽입하면 오류가 발생합니다.포함시키다{}, 값이 안전하다는 것을 알지 않는 한. 내 말은 일반적으로 이것이 잘못되었다는 것입니다.

    sudo sh -c "foo \"$var\" | foo2"

    변수를 안전하게 전달하는 방법에는 여러 가지가 있습니다. 나는 그것들을 나열할 것이다(다른 것이 있을 수도 있다):

    var="$var" sudo -E sh -c 'foo "$var" | foo2'   # may or may not work depending on sudoers and security policy
    sudo var="$var" sh -c 'foo "$var" | foo2'      # may or may not work depending on sudoers and security policy
    sudo env var="$var" sh -c 'foo "$var" | foo2'
    sudo sh -c "foo ${var@Q} | foo2"               # if the main shell is Bash
    sudo sh -c 'foo "$1" | foo2' sh "$var"
    

    방법 1번은 다음과 같습니다.

    sudo foo "$var" | sudo foo2
    

    쉽고 안전합니다.

  • 귀하가 종료 상태 foo및/또는 foo2등에 관심이 있다고 가정하면 sudo sh -c 'foo | foo2 | foo3'귀하에게 제공되지 않습니다. 파이프를 실행한 후 이 정보를 저장하는 쉘(예: Bash with it $PIPESTATUS[@])을 사용하더라도 실행 중인 내부 쉘에서 sudo외부 메인 쉘로 정보를 안정적으로 전달하는 것은 사소한 작업이 아니며 지루한 코드(예: 내부 쉘)가 필요합니다. 및 외부 쉘 각각).

    다시 말하지만, 방법 1은 간단합니다.

    sudo foo | sudo foo2 | sudo foo3
    

    각각 sudo(작업이 성공적으로 완료되는 한)은 foo*해당 명령의 종료 상태를 전달합니다. 이제 필요한 것은 메인 셸이 파이프라인에 있는 각 명령의 종료 상태를 알려줄 수 있는 것뿐입니다( $PIPESTATUS[@]메인 셸이 Bash인 경우).

  • sudoers제한된 수의 명령을 실행할 수 있는 경우에는 sudo그렇지 않을 가능성이 높습니다 sh(다른 무제한 쉘 또는 쉘 유사 유틸리티와 함께, 그렇지 않으면 어떤 명령이라도 실행할 수 있기 때문입니다 sudo). foo, foo2foo3가 허용되지만 쉘이 허용하지 않는 경우 sudo방법 1이 유일한 옵션입니다.


더 넓은 관점

다음과 같이 동작하는 다른 명령이 있습니다 sudo: nohup,,,,...niceioniceunshare

그것은 사실 이기도 echo합니다. 당신은 echo여기 있을 거라고 는 예상하지 못했어요

echo foo | foo2 | foo3

|와 나머지를 인수로 사용합니다 . 껍질에서 꺼내면 foo그게 전부입니다. 거의 아무도 놀라지 않습니다.

any(?) shell 에 echo내장되어 있습니다 . 즉, 쉘의 일부입니다. "내장"은 쉘이 외부 echo실행 파일을 실행하지 않고 에코 작업 자체를 처리하지만 내장은 외부 echo(그러나 신호와 관련된 몇 가지 미묘함이 있습니다.).

경우에 따라 다르게 동작하는 명령이 하나 이상 있는데, time이는 별도의 실행 파일이며 이렇게 호출하면 sudo질문의 맥락에서와 마찬가지로 동작합니다. 예를 들면 다음과 같습니다.

command time -p sleep 2 | sleep 4

유휴 OS에서는 2초 동안 실시간으로 보고되어야 합니다( timestderr로 인쇄되므로 파이프에도 불구하고 보고서를 계속 볼 수 있습니다). 그러나 Bash time에서는핵심 단어이는 Bash가 후속 콘텐츠를 구문 분석하는 방식을 변경합니다. 이는 추가 셸 생성으로 인한 편견 없이 전체 파이프라인(또는 셸 루프 등을 포함한 셸 코드 조각)을 측정할 수 있도록 의도적으로 수행되었습니다. 이 시도:

# in Bash
time -p sleep 2 | sleep 4

보고서에는 4초가 표시됩니다.

비교하다이 문제그리고 내 대답.

답변4

예, 하지만 명령은 ;, |또는로 끝납니다.&&||

아니요, 모든 복잡한 명령(예: a|b)이나 스크립트에서는 작동하지 않습니다.

관련 정보