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