#bash #shell
#bash #оболочка
Вопрос:
Это двоичный файл the_binary
:
#include <stdio.h>
int main(void){
char rbuf[10];
int ret;
if((ret = read(0, rbuf, 10)) < 0){
}
printf("read content:%sn",rbuf);
return 0;
}
Это сценарий bash:
#!/bin/bash
bash -ic "/bin/echo $$"
./the_binary
Попробуйте, вы заметите, что
➜ test ./the_script.sh # clarify: test is the part of prompt, but not the commmand, please ignore it
hello
[1] 25407 suspended (tty input) ./bash.sh
Насколько я знаю, bash -ic "/bin/echo hello"
что-то сделал, чтобы заставить двоичный файл отправлять SIGTTIN
сигнал процессу, выполняющему скрипт.
Но что произошло? Какова семантика bash -ic
?
Другие проблемные сценарии:
#!/bin/bash
bash -ic "/bin/echo hello"
bash -ic "/bin/echo hello"
и,
#!/bin/bash
bash -ic "/bin/echo hello"
python -ic "print 'hello'"
ОТРЕДАКТИРОВАНО: переименуйте двоичный файл, чтобы прояснить проблему
Комментарии:
1. Что
test
здесь? Это не стандартная команда.2.
bash -i
делает оболочку интерактивной, даже если стандартный ввод не является терминалом;test
выполняется ли его аргумент?3. Я не следую вашим примерам. Похоже, что вы запускаете встроенный bash
test
с файлом в качестве аргумента, но это не приведет к запуску скрипта. Он просто вернет 0.4.
SIGTTIN
происходит, когда программа, работающая в фоновом режиме, пытается выполнить чтение с терминала. Похоже, в вашем вопросе нет ничего, что запускает скрипт в фоновом режиме, но, возможно, это как-то связано с вашей версиейtest
. Вам действительно следует избегать присвоения вашим собственным программам того же имени, что и стандартные команды Unix, такие какread
andtest
.5. извините, я использую здесь zsh,
test
это просто имя каталога. Я удалил его.
Ответ №1:
Это bash пытается сделать что-то умное (снова! Я до сих пор помню shellshock. И здесь (на китайском языке) еще один).
strace -f
сценарий, и вы заметите, что SIGTTIN
он отправляется bash, а не ядром. Найдите исходный код, и вы увидите это в jobs.c:
if (shell_pgrp == 0)
{
shell_pgrp = getpid ();
setpgid (0, shell_pgrp);
tcsetpgrp (shell_tty, shell_pgrp);
}
while ((terminal_pgrp = tcgetpgrp (shell_tty)) != -1)
{
if (shell_pgrp != terminal_pgrp)
{
SigHandler *ottin;
ottin = set_signal_handler(SIGTTIN, SIG_DFL);
kill (0, SIGTTIN);
set_signal_handler (SIGTTIN, ottin);
continue;
}
break;
}
Почему второй (и третий, если вы его туда поместите) bash отправляет SIGTTIN
, но не первый?
Потому что в первый раз shell_pgrp == terminal_pgrp
(процесс, выполняющий сценарий). Затем интерактивный bash устанавливает себя в качестве группового процесса и группы процессов переднего плана. Затем он завершается.
Второй (и третий, если у вас есть) bash видит, что группа процессов — это процесс, выполняющий сценарий (это новая группа), но группа процессов переднего плана терминала по-прежнему является завершенным первым bash (исполнитель не выполняет никакого управления заданием, поскольку он выполняет сценарий неактивно).). Итак shell_pgrp != terminal_pgrp
, и kill
часть, описанная выше, выполняется.
man 4 tty_ioctl
и tcsetpgrp
если вам нужны некоторые документы.
zsh так не убивает.
Для этого скрипта:
#!/bin/bash
bash -ic "which mvn"
python -ic "print('hello')"
Вы не получаете SIGTTIN
. Вместо этого вы получаете a SIGTTOU
, потому что Python пытается что-то вывести, пока это не группа процессов переднего плана (первый, завершенный bash). (И если вы действительно получаете a SIGTTIN
, это потому python -i
, что по определению считывается с терминала. SIGTTOU
может не отправляться из ядра в зависимости от настроек вашего терминала.)