Estoy ejecutando Debian Stretch, todos los comandos a continuación (dash y bash ) se ingresa en bash.
El whoami parece que nunca se ejecuta como el usuario test en guión como en los códigos a continuación.
$ sudo dash << 'end'
> su test
> whoami
> end
root
$ sudo bash << 'end'
> su test
> whoami
> end
test
Respuesta aceptada:
Considere este ejemplo en su lugar:
$ cat f
grep pos /proc/self/fdinfo/0
IFS= read -r var
echo A
echo B
printf '%s\n' "var=$var"
$ bash < f
pos: 29
B
var=echo A
$ dash < f
pos: 85
A
B
var=
Como puede ver, en ese momento el grep se ejecuta el comando, la posición dentro de stdin está al final del archivo con dash , y justo después de la nueva línea que sigue al grep comando en bash .
El echo A el comando se ejecuta con dash pero en el caso de bash , se alimenta como entrada para read .
Lo que pasó es que dash leer toda la entrada (en realidad, un bloque de texto) mientras bash lea una línea a la vez antes de ejecutar los comandos.
Para hacerlo, bash necesitaría leer un byte a la vez para asegurarse de que no lea más allá de la nueva línea, pero cuando la entrada es un archivo normal (como en el caso de mi f archivo anterior, pero también para documentos aquí que bash implementa como archivos temporales, mientras que dash usa canalizaciones), bash lo optimiza leyendo por bloques y buscando hacia atrás hasta el final de la línea, que puedes ver con strace en Linux:
$ strace -e read,lseek bash < f
[...]
lseek(0, 0, SEEK_CUR) = 0
read(0, "grep pos /proc/self/fdinfo/0\nIFS"..., 85) = 85
lseek(0, -56, SEEK_CUR) = 29
pos: 29
[...]
$ strace -e read,lseek dash < f
read(0, "grep pos /proc/self/fdinfo/0\nIFS"..., 8192) = 85
pos: 85
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=12422, si_uid=1000, si_status=0, si_utime=0, si_stime=0} ---
read(0, "", 1) = 0
[...]
Cuando stdin es un dispositivo terminal, cada read() devuelve las líneas enviadas por el terminal, por lo que generalmente verá un comportamiento similar en bash y dash .
En tu caso, podrías hacer:
sudo dash << 'end-of-script'
su test <<"end"
whoami
end
end-of-script
o mejor:
sudo sh -c '
su test -c whoami
'
o incluso mejor:
sudo -u test whoami