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때문입니다 ( 호환 모드에서).bashENOEXECexecvesh

답변2

-s옵션을 사용하지 않기 때문에 sudo(Ubuntu 12.04 LTS에 정의됨)을 사용하여 _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더 많은 답변이 가능합니다.

관련 정보