Ich werde auf Debian Stretch ausgeführt, alle folgenden Befehle (dash und bash ) wird in bash eingegeben.
Der whoami Schein wird nie als Benutzer test ausgeführt im Bindestrich wie in den folgenden Codes.
$ sudo dash << 'end'
> su test
> whoami
> end
root
$ sudo bash << 'end'
> su test
> whoami
> end
test
Akzeptierte Antwort:
Betrachten Sie stattdessen dieses Beispiel:
$ 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=
Wie Sie sehen können, ist zur Zeit der grep Befehl ausgeführt wird, ist die Position innerhalb von stdin am Ende der Datei mit dash , und direkt nach dem Zeilenumbruch, der auf grep folgt Befehl in bash .
Das echo A Befehl wird von dash ausgeführt aber im Fall von bash , wird es als Eingabe an read übergeben .
Was passiert ist, ist dieser dash Lesen Sie die gesamte Eingabe (eigentlich einen Textblock) während bash Lesen Sie eine Zeile nach der anderen, bevor Sie Befehle ausführen.
Dazu bash müsste jeweils ein Byte lesen, um sicherzustellen, dass es nicht über die neue Zeile hinaus gelesen wird, aber wenn die Eingabe eine normale Datei ist (wie im Fall meiner f Datei oben, sondern auch für Here-Dokumente, die bash als temporäre Dateien implementiert, während dash verwendet Pipes), bash optimiert es, indem es blockweise liest und bis zum Ende der Zeile zurücksucht, was Sie mit strace sehen können unter 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
[...]
Wenn stdin ein Endgerät ist, wird jeder read() gibt die vom Terminal gesendeten Zeilen zurück, sodass Sie im Allgemeinen ein ähnliches Verhalten in bash sehen und dash .
In Ihrem Fall könnten Sie Folgendes tun:
sudo dash << 'end-of-script'
su test <<"end"
whoami
end
end-of-script
oder besser:
sudo sh -c '
su test -c whoami
'
oder noch besser:
sudo -u test whoami