shebang 라인 없이 쉘 스크립트를 실행하기 위해 sudo를 사용할 쉘은 무엇입니까?

shebang 라인 없이 쉘 스크립트를 실행하기 위해 sudo를 사용할 쉘은 무엇입니까?

내 환경은 Ubuntu 12.04 LTS이고 sudo버전은 1.8.3p1입니다.

먼저 일반 사용자로 로그인합니다.

$ whoami
fin

$ cat /etc/passwd | grep -i "root\|fin"
root:x:0:0:root:/root:/bin/bash
fin:x:1000:1000:This is a normal user:/home/fin:/bin/bash

$ ls -l /bin/sh
lrwxrwxrwx 1 root root 4 Mar 30  2012 /bin/sh -> dash

$ ls -l /bin/bash
-rwxr-xr-x 1 root root 920788 Apr  3  2012 /bin/bash

$ echo $SHELL
/bin/bash

$ ps | grep "$$" | awk '{ print $4 }'
bash

$ ls -l ./test.sh
-rwxr-xr-x 1 fin fin 37 Sep 27 16:46 test.sh

$ cat ./test.sh
ps | grep "$$" | awk '{ print $4 }'

$ ./test.sh
bash

$ sudo ./test.sh
sh

나는 루트가 를 사용한다는 것을 보여주므로 bash마지막 출력도 다음과 같아야 한다고 생각합니다 . 에 대한 요점이 누락되었습니까 ?/etc/passwdbashsudo

답변1

Linux에서 와 같이 정의된 것과 _PATH_BSHELL유사 하게 사용됩니다 . 이는 또는 예를 들어 실행될 때와 동일해야 합니다 .execvp()/bin/sh/usr/include/paths.henvfind -exec

확실히 사용자의 로그인 셸을 사용해서는 안 됩니다. bash위에서 보고 있는 사실은 bash이를 실행하려고 시도하는 것(해당 명령줄에 입력한 셸)이 ENOEXEC오류 코드를 받으면 대신( 호환 모드 execve에서) 자체적으로 해석하기로 결정하기 때문입니다.sh

답변2

-s옵션을 사용하지 않기 때문에 (Ubuntu 12.04 LTS에서 정의된 ) sudo을 사용하여 실행을 설정합니다 . 소스 코드 살펴보기 :_PATH_BSHELL/usr/include/paths.h$SHELLsudo

/* Stash user's shell for use with the -s flag; don't pass to plugin. */
    if ((ud->shell = getenv("SHELL")) == NULL || ud->shell[0] == '\0') {
    ud->shell = pw->pw_shell[0] ? pw->pw_shell : _PATH_BSHELL;
    }

-s옵션을 사용하는 경우 다음 대신에 sudo옵션을 사용합니다 .$SHELL_PATH_BSHELL

$ cat ./test.sh
ps | grep "$$" | awk '{ print $4 }'

$ ./test.sh
bash

$ sudo -s ./test.sh
bash

답변3

커널은 바이너리 실행 가능 이미지만 실행할 수 있습니다. 그렇다면 스크립트는 어떻게 실행되나요? 결국 my_script_without_shebang쉘 프롬프트에 입력해도 오류가 발생하지 않습니다 ENOEXEC. 스크립트 실행은 커널이 아니라 셸에서 수행됩니다. 셸의 실행 코드는 일반적으로 다음과 같습니다.

/* try to run the program */
execl(program, basename(program), (char *)0);

/* the exec failed -- maybe it is a shell script without shebang? */
if (errno == ENOEXEC)
    execl ("/bin/sh", "sh", "-c", program, (char *)0);

Shebang 없이 더미 쉘 스크립트를 추적하여 이를 확인할 수 있습니다.

cat > /tmp/foo.sh <<EOF
echo
EOF

chmod u+x /tmp/foo.sh

strace /tmp/foo.sh 2>&1 | grep exec
execve("/tmp/foo.sh", ["/tmp/foo.sh"], [/* 28 vars */]) = -1 ENOEXEC (Exec format error)

그런 다음 Stephane이 설명한 대로 실행이 진행됩니다. 기본 셸이 사용됩니다(위 코드 조각에서는 하드 코딩되어 있습니다).이 좋은 UNIX FAQ더 많은 답변을 드릴 수 있습니다.

관련 정보