Je suis exécuté sur debian stretch, toutes les commandes ci-dessous (dash
et bash
) est entré dans bash.
Le whoami
semble ne jamais fonctionner en tant qu'utilisateur test en tiret comme dans les codes ci-dessous.
$ sudo dash << 'end'
> su test
> whoami
> end
root
$ sudo bash << 'end'
> su test
> whoami
> end
test
Réponse acceptée :
Considérez plutôt cet exemple :
$ 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=
Comme vous pouvez le voir, à l'époque le grep
la commande est exécutée, la position dans stdin est à la fin du fichier avec dash
, et juste après la nouvelle ligne qui suit le grep
commande dans bash
.
Le echo A
la commande est exécutée par dash
mais dans le cas de bash
, il est alimenté en entrée pour read
.
Ce qui s'est passé, c'est ce dash
lire toute l'entrée (en fait, un bloc de texte) pendant que bash
lisez une ligne à la fois avant d'exécuter des commandes.
Pour ce faire, bash
aurait besoin de lire un octet à la fois pour s'assurer qu'il ne lit pas au-delà de la nouvelle ligne, mais lorsque l'entrée est un fichier normal (comme dans le cas de mon f
fichier ci-dessus, mais aussi pour les documents ici que bash implémente en tant que fichiers temporaires, tandis que dash
utilise des pipes), bash
l'optimise en lisant par blocs et en revenant à la fin de la ligne, ce que vous pouvez voir avec strace
sous 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 [...]
Lorsque stdin est un terminal, chaque read()
renvoie les lignes telles qu'elles sont envoyées par le terminal, vous voyez donc généralement un comportement similaire dans bash
et dash
.
Dans votre cas, vous pourriez faire :
sudo dash << 'end-of-script'
su test <<"end"
whoami
end
end-of-script
ou mieux :
sudo sh -c '
su test -c whoami
'
ou encore mieux :
sudo -u test whoami