Go语言:如何彻底禁用父进程与子进程的STDIN?
彻底禁用Go父进程与子进程的STDIN解决方案
背景
我从Go主进程的goroutine中启动子进程,但STDIN文件描述符(FD)会被子进程继承。目标是将子进程的STDIN设置为nil,彻底禁止子进程读取任何标准输入。
已尝试的方法
我试过以下两种方式,但未达到预期效果:
os.Stdin = nil os.Stdin = os.NewFile(uintptr(syscall.Stdin), "/dev/null")
临时解决方案
目前仅找到一个不够规范的临时处理办法:
func init() { go func() { for { io.Copy(os.Stdout, os.Stdin) } }() }
补充更新
后续发现,如果子进程(比如我当前启动的FFUF)直接读取/dev/tty,os.Stdin = nil完全无效。FFUF相关的终端读取代码如下:
go func() { tty, err := os.Open("/dev/tty") if err != nil { fmt.Println(err) return } defer tty.Close() inreader := bufio.NewScanner(tty) inreader.Split(bufio.ScanLines) started <- true for inreader.Scan() { fmt.Printf("handle: " + inreader.Text()) } }()
最优解决方案
1. 针对子进程继承STDIN的规范处理
不需要修改父进程的STDIN,直接在启动子进程时通过os/exec的Cmd结构体配置输入源,这是最可靠的方式:
import "os/exec" func startSubprocess() error { cmd := exec.Command("your-subprocess-command", "arg1", "arg2") // 将子进程STDIN绑定到/dev/null(Go 1.16+可直接用os.DevNull) cmd.Stdin = os.DevNull // 启动子进程 if err := cmd.Start(); err != nil { return err } // 可选:等待子进程结束 // return cmd.Wait() return nil }
这种方式会让子进程的STDIN指向空设备,无法读取任何输入,也不会继承父进程的STDIN文件描述符。
2. 针对子进程直接读取/dev/tty的情况
如果子进程绕过STDIN直接读取终端(比如FFUF的逻辑),可以通过两种方式解决:
- 利用工具自带参数禁用交互:FFUF提供了
-noninteractive参数,启动时添加该参数即可跳过终端读取:
cmd := exec.Command("ffuf", "-noninteractive", "-u", "http://example.com/FUZZ", "-w", "wordlist.txt") cmd.Stdin = os.DevNull // 后续启动逻辑...
- 脱离终端环境:在启动子进程前调用
syscall.Setsid()让父进程脱离当前终端,子进程也会失去终端访问权限(注意:此操作会让父进程本身也脱离终端,需根据场景判断是否适用):
import "syscall" func startSubprocessWithoutTTY() error { // 脱离当前终端会话 if err := syscall.Setsid(); err != nil { return err } cmd := exec.Command("ffuf", "-u", "http://example.com/FUZZ", "-w", "wordlist.txt") cmd.Stdin = os.DevNull return cmd.Start() }
内容的提问来源于stack exchange,提问作者Dušan Panić
相关产品推荐
相关产品推荐

