在bash -ic" / bin / echo你好"`bash脚本时出现意外的SIGTTIN

时间:2016-10-07 15:31:15

标签: bash shell

这是二进制the_binary

#include <stdio.h>   
int main(void){   
    char rbuf[10];   
    int ret;
    if((ret = read(0, rbuf, 10)) < 0){   
    }   
    printf("read content:%s\n",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 个答案:

答案 0 :(得分:3)

它试图做一些聪明的事情(再一次!我还记得shellshock。而here(中文)是另一个。)

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_pgrpkill部分会执行。

如果您需要一些文档,请

man 4 tty_ioctltcsetpgrp

zsh并不像这样杀人。

对于这个脚本:

#!/bin/bash
bash -ic "which mvn"
python -ic "print('hello')"

您没有收到SIGTTIN。您会收到一个SIGTTOU,因为Python尝试输出的内容虽然不是前台进程组(第一个是退出的bash)。 (如果确实收到SIGTTIN,那么因为python -i的定义,从终端读取。SIGTTOU可能无法从内核发送,具体取决于您的终端设置。)