从bash中启动进程而不继承文件描述符

4
我想从我的bash脚本启动一个新进程,该进程不会继承父文件描述符。我无法更改这些文件描述符的创建方式。
使用情况: 应用程序错误 -> 错误挂钩 -> 终止进程并重新启动
有一个类似于Windows的主题 start without inheritance of parents file descriptors,但它在Linux上不起作用。
在shell中是否可能实现这一点?
谢谢
更新 我知道我可以自己关闭这些描述符,我只是想确保无法启动具有某些神奇选项的子级以跳过复制文件描述符。(因为这个选项听起来对我很合理)
2个回答

7

一般情况下无法阻止文件描述符的继承。在C语言中,可以使用FD_CLOEXEC,但仍然只是部分解决方案,如这里所解释的那样。

关闭那些不需要的文件描述符:

exec 3>&- #close fd 3.

一个更长的例子:

#! /bin/bash

# Open some file descriptors
for n in $(seq 10 20) ; do
    eval "exec $n>/dev/null"
done

# List them
echo -n "$BASHPID: " ; ls -v /proc/$BASHPID/fd

# Start a sub process without them
(
    # List inherited descriptors
    echo -n "$BASHPID: " ; ls -v /proc/$BASHPID/fd

    # Close all but stdio
    SELF=$BASHPID
    FDS=$(find /proc/$SELF/fd -type l -printf '%f\n')
    # The following will even try to close the fd for the find sub
    # shell although it is already closed. (0: stdin, 1: stdout, 2:
    # stderr, 3: find)
    echo -n 'Closing:'
    for n in $FDS ; do
    if ((n > 2)) ; then
        echo -n " $n"
        eval "exec $n>&-"
    fi
    done
    echo

    # List remaining
    echo -n "$BASHPID: " ; ls -v /proc/$BASHPID/fd

    # Do what you want
)

# Original shell has sill all descriptors
echo -n "$BASHPID: " ; ls -v /proc/$BASHPID/fd

但是你怎么知道哪些描述符是打开的? - Roberto Reale
1
你已经打开了它们!ls /proc/$$/fd 可以帮助你记住。 - ceving
当然,但是如果我想关闭我打开或继承的每个文件描述符怎么办? - Roberto Reale
@RobertoReale Bash 有一个 for 循环。 - ceving
1
@ceving,ls /proc/$$/fd将列出顶层shell进程的FD。如果您有打开某些内容并再次分叉的子shell,则此方法无法帮助您。奇怪的是,这可能会在不知不觉中发生,例如由于管道。在子shell中使用$BASHPID而不是$$ - Piotr Findeisen
显示剩余5条评论

0
你可以编写一个函数来关闭Bash的10个可继承文件描述符:
fdcloexec () {
  "$@" 0>&- 1>&- 2>&- 3>&- 4>&- 5>&- 6>&- 7>&- 8>&- 9>&-
}

然后你将调用fdcloexec your command here来执行你的命令而不继承文件描述符。


1
其他描述符(例如13)也会被继承,例如进入子shell ... | { ... 在此处的子shell ... }。至少在我的bash中是这样。 - Piotr Findeisen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接