Používám debian stretch, všechny níže uvedené příkazy (dash
a bash
) je vstupem do bash.
whoami
Zdá se, že se nikdy nespustí jako uživatel test v pomlčce jako v níže uvedených kódech.
$ sudo dash << 'end'
> su test
> whoami
> end
root
$ sudo bash << 'end'
> su test
> whoami
> end
test
Přijatá odpověď:
Zvažte místo toho tento příklad:
$ 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=
Jak můžete vidět, v té době grep
Pokud je příkaz spuštěn, pozice v stdin je na konci souboru s dash
a hned za nový řádek, který následuje za grep
příkaz v bash
.
echo A
příkaz je spuštěn pomocí dash
ale v případě bash
, je přiváděn jako vstup pro read
.
Stalo se to dash
číst celý vstup (ve skutečnosti blok textu), zatímco bash
číst jeden řádek po druhém před spuštěním příkazů.
Chcete-li to provést, bash
bude muset číst jeden bajt po druhém, aby se ujistil, že nečte za nový řádek, ale když je vstupem běžný soubor (jako v případě mého f
výše, ale také pro dokumenty zde, které bash implementuje jako dočasné soubory, zatímco dash
používá potrubí), bash
optimalizuje jej čtením po blocích a vyhledáváním zpět na konec řádku, který můžete vidět pomocí strace
v systému 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 [...]
Když je stdin koncové zařízení, každé read()
vrací řádky odeslané terminálem, takže v bash
obecně vidíte podobné chování a dash
.
Ve vašem případě můžete udělat:
sudo dash << 'end-of-script'
su test <<"end"
whoami
end
end-of-script
nebo lépe:
sudo sh -c '
su test -c whoami
'
nebo ještě lépe:
sudo -u test whoami