"스도-s" 셸에서 명령을 실행하지만 와일드카드나 메타문자가 작동하지 않습니다.

"스도-s" 셸에서 명령을 실행하지만 와일드카드나 메타문자가 작동하지 않습니다.

사용시 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제대로 작동합니다. 이 경우에는 $SHELLbash이므로 다음과 같습니다.

$ 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 -ssudo -i
  • $SHELL -c스크립트가 단일 문자열을 사용하지만 여러 매개변수를 사용하는 경우 sudo -s스크립트는 매개변수로부터 어떻게 조합됩니까?
  • 쉘에서 명령을 실행하여 이를 수행하는 안정적인 방법은 무엇입니까 sudo?

답변1

간단히 말해서:"--shell" 또는 "--login" 옵션에 대해 명령을 실행하면 공백을 포함한 sudo모든 메타 문자( 제외)를 포함하여 대부분의 문자가 이스케이프됩니다(백슬래시 이스케이프 사용) $.

이로 인해 셸을 사용하려는 모든 사용 사례가 중단되어 sudo -s대부분의 경우 셸 명령 실행이 적합하지 않게 됩니다.필요쉘 명령으로 실행하십시오.

대신에 or (또는 예상되는 모든 것 ) sudo -s을 사용하십시오 . 대신에 ( 루트의 쉘이 다시 bash라고 가정합니다.)sudo sh -c '...'sudo bash -c '...'$SHELLsudo -isudo 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.)

관련 정보