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
|
foo3
foo | foo2 | foo3
|
sudo
sudo
다음을 사용하여 여러 명령을 실행하는 두 가지 방법:
해석하려면 쉘이 필요합니다 |
. 이는 두 가지 기본 접근 방식으로 이어집니다.
sudo foo | sudo foo2 | sudo foo3
메인 하우징 처리 배관;sudo sh -c 'foo | foo2 | foo3'
새로운 높은 인클로저가 덕트를 처리합니다.
와 유사 &&
및/또는 ||
대체 또는 유사합니다 |
.
사례 2에서는 기본 쉘이 시작되고 sudo
while은 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
,foo2
및foo3
가 허용되지만 쉘이 허용하지 않는 경우sudo
방법 1이 유일한 옵션입니다.
더 넓은 관점
다음과 같이 동작하는 다른 명령이 있습니다 sudo
: nohup
,,,,...nice
ionice
unshare
그것은 사실 이기도 echo
합니다. 당신은 echo
여기 있을 거라고 는 예상하지 못했어요
echo foo | foo2 | foo3
|
와 나머지를 인수로 사용합니다 . 껍질에서 꺼내면 foo
그게 전부입니다. 거의 아무도 놀라지 않습니다.
any(?) shell 에 echo
내장되어 있습니다 . 즉, 쉘의 일부입니다. "내장"은 쉘이 외부 echo
실행 파일을 실행하지 않고 에코 작업 자체를 처리하지만 내장은 외부 echo
(그러나 신호와 관련된 몇 가지 미묘함이 있습니다.).
경우에 따라 다르게 동작하는 명령이 하나 이상 있는데, time
이는 별도의 실행 파일이며 이렇게 호출하면 sudo
질문의 맥락에서와 마찬가지로 동작합니다. 예를 들면 다음과 같습니다.
command time -p sleep 2 | sleep 4
유휴 OS에서는 2초 동안 실시간으로 보고되어야 합니다( time
stderr로 인쇄되므로 파이프에도 불구하고 보고서를 계속 볼 수 있습니다). 그러나 Bash time
에서는핵심 단어이는 Bash가 후속 콘텐츠를 구문 분석하는 방식을 변경합니다. 이는 추가 셸 생성으로 인한 편견 없이 전체 파이프라인(또는 셸 루프 등을 포함한 셸 코드 조각)을 측정할 수 있도록 의도적으로 수행되었습니다. 이 시도:
# in Bash
time -p sleep 2 | sleep 4
보고서에는 4초가 표시됩니다.
비교하다이 문제그리고 내 대답.
답변4
예, 하지만 명령은 ;
, |
또는로 끝납니다.&&
||
아니요, 모든 복잡한 명령(예: a|b
)이나 스크립트에서는 작동하지 않습니다.