GNU/Linux >> LINUX-Kenntnisse >  >> Linux

Warum funktioniert das Parent Shell Here-Dokument nicht für Unterbefehle in Dash, aber Bash funktioniert?

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

Linux
  1. Anpassen der Bash-Shell

  2. Warum funktioniert das ~/.bash_profile nicht?

  3. Warum ist die PGID der untergeordneten Prozesse nicht die PGID des übergeordneten Prozesses?

  4. Zirkuläre Namensreferenzen in der Bash-Shell-Funktion, aber nicht in Ksh?

  5. Linux – Warum funktioniert Locale Es_mx, aber nicht Es?

Warum funktioniert „zip“ in einer For-Schleife, wenn die Datei existiert, aber nicht, wenn sie nicht existiert?

Warum funktioniert dieses „beim Lesen“ in einem Terminal, aber nicht in einem Shell-Skript?

Wie liest man das gesamte Shell-Skript, bevor man es ausführt?

Warum ist Bash überall (in den meisten, wenn nicht allen Linux-Distributionen)?

Warum funktioniert „dd“ nicht zum Erstellen eines bootfähigen USB-Sticks?

Warum ist SUID für Shell-Skripte deaktiviert, aber nicht für Binärdateien?