Saya menjalankan debian stretch, semua perintah di bawah ini (dash
dan bash
) dimasukkan ke bash.
whoami
sepertinya tidak pernah dijalankan sebagai pengguna test dalam tanda hubung seperti pada kode di bawah ini.
$ sudo dash << 'end'
> su test
> whoami
> end
root
$ sudo bash << 'end'
> su test
> whoami
> end
test
Jawaban yang Diterima:
Pertimbangkan contoh ini sebagai gantinya:
$ 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=
Seperti yang Anda lihat, pada saat grep
perintah dijalankan, posisi dalam stdin berada di akhir file dengan dash
, dan tepat setelah baris baru yang mengikuti grep
perintah di bash
.
echo A
perintah dijalankan oleh dash
tetapi dalam kasus bash
, diumpankan sebagai input untuk read
.
Apa yang terjadi adalah dash
baca seluruh input (sebenarnya, satu blok teks) saat bash
membaca satu baris pada satu waktu sebelum menjalankan perintah.
Untuk melakukannya, bash
perlu membaca satu byte pada satu waktu untuk memastikan itu tidak membaca melewati baris baru, tetapi ketika inputnya adalah file biasa (seperti dalam kasus f
saya file di atas, tetapi juga untuk dokumen di sini yang diimplementasikan bash sebagai file sementara, sementara dash
menggunakan pipa), bash
mengoptimalkannya dengan membaca per blok dan mencari kembali ke akhir baris, yang dapat Anda lihat dengan strace
di 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 [...]
Ketika stdin adalah perangkat terminal, setiap read()
mengembalikan baris seperti yang dikirim oleh terminal, jadi Anda biasanya melihat perilaku serupa di bash
dan dash
.
Dalam kasus Anda, Anda dapat melakukan:
sudo dash << 'end-of-script'
su test <<"end"
whoami
end
end-of-script
atau lebih baik:
sudo sh -c '
su test -c whoami
'
atau bahkan lebih baik:
sudo -u test whoami