사용시 sudo -s
(이하"--shell" 옵션), "sudo"에 명령을 전달할 수 있습니다. 이 경우 대상 사용자로 "sudo"가 시작한 셸에서 명령이 실행됩니다.
(마찬가지로 sudo -i
다음과 같이 사용할 수도 있습니다."--로그인" 옵션, 또한 쉘을 시작하고 비슷한 방식으로 동작하는 명령을 유사하게 받아들입니다. )
대부분의 경우 셸을 통해 sudo에서 명령을 실행하는 것이 중요할 수 있습니다.
- 현재 사용자가 액세스할 수 없지만 해당 루트는 액세스할 수 있는 디렉토리에서 와일드카드를 사용하는 경우 와일드카드를 올바르게 확장하려면 루트 쉘에서 명령을 실행해야 합니다.
- 파이프라인에 연결된 많은 명령을 사용하여 전체 파이프라인을 실행합니다(
|
). - 등
for
의 쉘 내장 기능을 실행할 때if
단일 스크립트 아래에서 완전한 작은 인라인 "스크립트"를 실행하는 것이sudo
유용할 수 있습니다 .
선적 서류 비치"-s" 옵션말했다(강조):
환경 변수
SHELL
(설정된 경우)로 지정된 쉘 또는 호출하는 사용자의 비밀번호 데이터베이스 항목으로 지정된 쉘을 실행합니다.명령이 지정되면 쉘의 명령을 통해 전달됩니다.-씨옵션. 명령이 지정되지 않으면 대화형 쉘이 실행됩니다. 대부분의 셸은 대화형 세션과 비교하여 명령을 지정할 때 다르게 동작합니다. 자세한 내용은 셸 설명서를 참조하세요.
즉, sudo -s
명령이 전달 되면 -c
"script"가 포함된 문자열을 가져온 다음 이를 셸 스크립트로 실행하는 options 를 사용하여 셸에 전달됩니다.
문서에서는 이 옵션을 사용하는 방법에 대해 더 이상 설명하지 않으며 "자세한 내용은 셸 설명서를 참조하세요"라고 말하는 것 외에는 예제도 제공하지 않습니다. 이는 수신된 명령이 통과되었음을 의미합니다.곧장쉘에 대한 옵션 -c
. 그러나 이는 사실이 아닌 것으로 밝혀졌습니다.
여러 단어가 포함된 쉘 스크립트를 전달하면 실패합니다.
$ sudo -s 'ls -ld /var/empty'
/bin/bash: ls -ld /var/empty: No such file or directory
오류 메시지는 전체 문자열을 간단한 명령으로 실행하려고 한다는 의미입니다... 흠, 알겠습니다. 공백을 추가하면 작동할까요? 예, 다음과 같은 일이 발생합니다.
$ sudo -s ls -ld /var/empty
drwxr-xr-x. 3 root root 18 Jul 12 21:48 /var/empty
하지만 쉘이 실제로 작동하는 방식은 그렇지 않습니다 . 홈 디렉토리에 대한 바로 가기와 같은 일부 메타 문자를 사용하여 작동 방식을 살펴 -c
보겠습니다 . sudo가 아닌 쉘이 확장되는 것을 방지하려면 따옴표 ~
가 ~
필요합니다(이 경우 /root
예상과 달리 루트가 아닌 사용자의 홈 디렉토리로 확장됩니다).
$ sudo -s ls '~'
ls: cannot access '~': No such file or directory
~
좋아, 그래서 이것은 작동하지 않습니다. 오류 출력은 거기에 리터럴을 남기기 때문에 확장이 발생하지 않았다는 것을 의미하는 것 같습니다 .
와일드카드는 어떻습니까? 또한 작동하지 않습니다.
$ sudo -s ls '/root/*.cfg'
ls: cannot access '/root/*.cfg': No such file or directory
두 경우 모두 명령을 실행하면 $SHELL -c
제대로 작동합니다. 이 경우에는 $SHELL
bash이므로 다음과 같습니다.
$ sudo bash -c 'ls ~'
anaconda-ks.cfg
$ sudo bash -c 'ls /root/*.cfg'
/root/anaconda-ks.cfg
한 가지 예외는 변수가 에서 작동하는 것 같다는 것입니다 sudo -s
. 예를 들면 다음과 같습니다.
$ sudo -s echo '$HOME'
/root
그래서:
- 여기서 무슨 일이 일어나고 있는 걸까요?
~
또는에 전달된 명령 에서 와일드카드와 메타 문자(예:)가 작동하지 않는 이유는 무엇입니까 ?sudo -s
sudo -i
$SHELL -c
스크립트가 단일 문자열을 사용하지만 여러 매개변수를 사용하는 경우sudo -s
스크립트는 매개변수로부터 어떻게 조합됩니까?- 쉘에서 명령을 실행하여 이를 수행하는 안정적인 방법은 무엇입니까
sudo
?
답변1
간단히 말해서:"--shell" 또는 "--login" 옵션에 대해 명령을 실행하면 공백을 포함한 sudo
모든 메타 문자( 제외)를 포함하여 대부분의 문자가 이스케이프됩니다(백슬래시 이스케이프 사용) $
.
이로 인해 셸을 사용하려는 모든 사용 사례가 중단되어 sudo -s
대부분의 경우 셸 명령 실행이 적합하지 않게 됩니다.필요쉘 명령으로 실행하십시오.
대신에 or (또는 예상되는 모든 것 ) sudo -s
을 사용하십시오 . 대신에 ( 루트의 쉘이 다시 bash라고 가정합니다.)sudo sh -c '...'
sudo bash -c '...'
$SHELL
sudo -i
sudo bash -l -c '...'
보고 있다sudo 소스코드 관련 부분, 다음 스니펫이 있습니다.
/* quote potential meta characters */
if (!isalnum((unsigned char)*src) && *src != '_' && *src != '-' && *src != '$')
*dst++ = '\\';
*dst++ = *src;
이 스니펫은 모든 매개변수의 모든 문자를 반복합니다. 문자가 영숫자, 밑줄, 대시 또는 달러 기호가 아닌 경우 백슬래시로 이스케이프됩니다.
즉, 와일드카드 문자 *
, 등 ?
이 , , [...]
로 이스케이프됩니다 .\*
\?
\[...\]
또한 , ~
, 같은 메타 문자는 ;
, , 로 이스케이프됩니다 .|
\~
\;
\|
공백이 있는 문자열은 ls /root
로 이스케이프됩니다 ls\ /root
.
어떤 이유로 $
이스케이프는 예외이므로 이스케이프되지 않은 상태 sudo -s echo '$HOME'
로 유지되므로 작동합니다 $
. (이것은 변수에서만 작동하며 form 에서도 작동하지 않습니다 ${HOME}
. 이 경우 중괄호가 이스케이프되어 표현식이 중단됩니다.)
이 인용문의 결과는 대부분의 경우필요하다sudo -s <command>
쉘을 루트로 실행하면 다음 형식의 이점을 실제로 누릴 수 없습니다 .
- 와일드카드 문자는 이스케이프 처리되어 와일드카드 문자로 사용할 수 없으므로 확장되지 않습니다.
- 파이프가
|
탈출되어 작동하지 않기 때문에 파이프가 작동하지 않습니다. for
및 같은 명령은if
일반적으로 를 사용하는 데 필요하며;
, 이 명령도 이스케이프되어 작동하지 않습니다. 개행 문자는 옵션이지만 이스케이프되지 않은 개행 문자를 도입하는 방법도 없는 것 같습니다.
간단히 말해서, 이 양식은 sudo -s <command>
와일드카드, 파이프, 스크립트 등이 관련되지 않은 경우에만 작동하는 것 같습니다. 하지만,일반적으로 이러한 명령을 실행하는 데 쉘이 실제로 필요하지 않습니다!이러한 경우에는 sudo <command>
일반적으로 사용하지 않고 단순히 실행하는 것만으로도 충분합니다.-s
sudo를 구현하게 된 동기가 무엇인지는 확실하지 않습니다. 어쩌면 추가하거나 제거하기 위한 것일 수도 있습니다 . 어쩌면 lookahead -s
때문일 수도 있습니다 . 이 경우 환경 변수가 설정되는 방식에 약간의 차이가 있습니다.-i
-s
해결책:해결 방법은 셸을 명시적으로 실행하는 것입니다 -c
.
여기에는 $SHELL
대상 사용자의 콘텐츠를 이해하는 것이 포함됩니다(현재 사용자와 일치하지 않을 수 있으므로 $SHELL
직접 사용이 항상 올바른 것은 아닙니다).
예를 들어 대신 다음을 sudo -s ls -l '/root/*.cfg'
사용합니다.
$ sudo bash -c 'ls -l /root/*.cfg'
그리고 sudo -i ls -l '~'
다음을 사용하세요:
$ sudo bash -l -c 'ls -l ~'
(bash에 대한 인수는 -l
에서 만든 쉘과 동일한 "로그인" 쉘을 생성합니다 sudo -i
.)