
Meu ambiente é Ubuntu 12.04 LTS e a sudo
versão é 1.8.3p1.
Primeiro eu faço login como usuário normal:
$ 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
Suponho que a última saída também deva ser bash
porque /etc/passwd
mostra que o root usa bash
, estou faltando algum ponto sudo
?
Responder1
Ele usa _PATH_BSHELL
como execvp()
which no Linux é definido como /bin/sh
em /usr/include/paths.h
. Deve ser o mesmo que quando executado com env
ou find -exec
por exemplo.
Certamente não deve usar o shell de login do usuário. O fato que você está vendo bash
acima é porque é bash
(o shell em que você insere a linha de comando) que tenta executá-lo e quando recebe um ENOEXEC
código de erro, execve
decide interpretá-lo consigo mesmo (no sh
modo de compatibilidade).
Responder2
Porque você não usa -s
a opção, então sudo
usará _PATH_BSHELL
(que é definido no /usr/include/paths.h
Ubuntu 12.04 LTS) para configurá-lo $SHELL
para execução. Olhando para sudo
o código-fonte:
/* 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;
}
Se você usar -s
a opção, sudo
usará seu $SHELL
em vez de _PATH_BSHELL
:
$ cat ./test.sh
ps | grep "$$" | awk '{ print $4 }'
$ ./test.sh
bash
$ sudo -s ./test.sh
bash
Responder3
O kernel só pode executar imagens binárias executáveis. Então, como os scripts são executados? Afinal, posso digitar my_script_without_shebang
em um prompt do shell e não recebo nenhum ENOEXEC
erro. A execução do script não é feita pelo kernel, mas pelo shell. O código exec no shell geralmente se parece com:
/* 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);
Você pode verificar isso rastreando um script de shell fictício sem 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)
Então, a execução prossegue conforme descrito por Stephane - o shell padrão é usado (no trecho de código acima é codificado).Este bom FAQ do UNIXpode responder mais.