Mi entorno es Ubuntu 12.04 LTS y la sudo
versión es 1.8.3p1.
Primero inicio sesión como usuario 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
Supongo que el último resultado también debería serlo bash
porque /etc/passwd
muestra que la raíz usa bash
, ¿me falta algún punto al respecto sudo
?
Respuesta1
Utiliza _PATH_BSHELL
como execvp()
que en Linux se define como /bin/sh
en /usr/include/paths.h
. Eso debería ser lo mismo que cuando se ejecuta con env
o find -exec
por ejemplo.
Ciertamente no debería utilizar el shell de inicio de sesión del usuario. El hecho de que estés viendo bash
arriba se debe a que es bash
(el shell en el que ingresas esa línea de comando) el que intenta ejecutarlo y cuando recibe un ENOEXEC
código de error execve
decide interpretarlo consigo mismo (en sh
modo de compatibilidad).
Respuesta2
Debido a que no usa -s
la opción, sudo
usará _PATH_BSHELL
(que está definida en /usr/include/paths.h
Ubuntu 12.04 LTS) para configurarla para $SHELL
que se ejecute. Mirando el sudo
código fuente:
/* 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;
}
Si usa -s
la opción, sudo
usará su $SHELL
en lugar de _PATH_BSHELL
:
$ cat ./test.sh
ps | grep "$$" | awk '{ print $4 }'
$ ./test.sh
bash
$ sudo -s ./test.sh
bash
Respuesta3
El kernel sólo puede ejecutar imágenes binarias ejecutables. Entonces, ¿cómo se ejecutan los scripts? Después de todo, puedo escribir my_script_without_shebang
en el símbolo del shell y no aparece ningún ENOEXEC
error. La ejecución del script no la realiza el kernel, sino el shell. El código ejecutivo en el shell generalmente se parece a:
/* 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);
Puede verificarlo rastreando un script de shell ficticio sin 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)
Entonces, la ejecución continúa como lo describió Stephane: se usa el shell predeterminado (en el fragmento de código anterior está codificado).Estas bonitas preguntas frecuentes sobre UNIXpuedo responder más.