你什么时候会使用额外的文件描述符?

dog*_*ane 93 shell bash io-redirection file-descriptors

我知道您可以创建一个文件描述符并将输出重定向到它。例如

exec 3<> /tmp/foo # open fd 3.
echo a >&3 # write to it
exec 3>&- # close fd 3.
Run Code Online (Sandbox Code Playgroud)

但是你可以在没有文件描述符的情况下做同样的事情:

FILE=/tmp/foo
echo a > "$FILE"
Run Code Online (Sandbox Code Playgroud)

我正在寻找一个很好的例子,说明何时必须使用额外的文件描述符。

Gil*_*il' 59

大多数命令都有一个输入通道(标准输入,文件描述符 0)和一个输出通道(标准输出,文件描述符 1),或者对它们自己打开的几个文件进行操作(因此你向它们传递文件名)。(这是标准错误 (fd 2) 的补充,它通常会一直过滤到用户。)但是,有时将命令用作来自多个源或多个目标的过滤器会很方便。例如,这里有一个简单的脚本,它将文件中的奇数行与偶数行分开

while IFS= read -r line; do
  printf '%s\n' "$line"
  if IFS= read -r line; then printf '%s\n' "$line" >&3; fi
done >odd.txt 3>even.txt
Run Code Online (Sandbox Code Playgroud)

现在假设您想对奇数行和偶数行应用不同的过滤器(但不将它们重新放在一起,这将是一个不同的问题,通常从 shell 中不可行)。在 shell 中,你只能通过管道将一个命令的标准输出传送到另一个命令;要通过管道传输另一个文件描述符,您需要先将其重定向到 fd 1。

{ while … done | odd-filter >filtered-odd.txt; } 3>&1 | even-filter >filtered-even.txt
Run Code Online (Sandbox Code Playgroud)

另一个更简单的用例是过滤命令的错误输出

exec M>&N将文件描述符重定向到脚本的其余部分的另一个文件描述符(或直到另一个此类命令再次更改文件描述符)。exec M>&N和之间的功能有些重叠somecommand M>&N。该exec形式更强大,因为它不必是嵌套:

exec 8<&0 9>&1
exec >output12
command1
exec <input23
command2
exec >&9
command3
exec <&8
Run Code Online (Sandbox Code Playgroud)

其他可能感兴趣的示例:

还有更多例子:

PS 这是一个令人惊讶的问题,来自该网站上使用通过 fd 3 重定向最受好评帖子的作者!

  • @Wildcard 你当然可以用其他工具做同样的事情。但是这个答案的目标是说明 shell 中的重定向。 (2认同)

For*_*rdi 20

这是使用额外 FD 作为 bash 脚本聊天控制的示例:

#!/bin/bash

log() {
    echo $* >&3
}
info() {
    echo $* >&4
}
err() {
    echo $* >&2
}
debug() {
    echo $* >&5
}

VERBOSE=1

while [[ $# -gt 0 ]]; do
    ARG=$1
    shift
    case $ARG in
        "-vv")
            VERBOSE=3
        ;;
        "-v")
            VERBOSE=2
        ;;
        "-q")
            VERBOSE=0
        ;;
        # More flags
        *)
        echo -n
        # Linear args
        ;;
    esac
done

for i in 1 2 3; do
    fd=$(expr 2 + $i)
    if [[ $VERBOSE -ge $i ]]; then
        eval "exec $fd>&1"
    else
        eval "exec $fd> /dev/null"
    fi
done

err "This will _always_ show up."
log "This is normally displayed, but can be prevented with -q"
info "This will only show up if -v is passed"
debug "This will show up for -vv"
Run Code Online (Sandbox Code Playgroud)

  • `exec {fd}&gt;&amp;1` 是一种更简洁的方法 (3认同)

小智 8

在命名管道 (fifos) 的上下文中,使用附加文件描述符可以启用非阻塞管道行为。

(
rm -f fifo
mkfifo fifo
exec 3<fifo   # open fifo for reading
trap "exit" 1 2 3 15
exec cat fifo | nl
) &
bpid=$!

(
exec 3>fifo  # open fifo for writing
trap "exit" 1 2 3 15
while true;
do
    echo "blah" > fifo
done
)
#kill -TERM $bpid
Run Code Online (Sandbox Code Playgroud)

请参阅:命名管道在脚本中过早关闭?

  • 你挖出了我的一个老问题:) 乍得是对的,你会遇到竞争条件。 (2认同)

Ada*_*ski 7

额外的文件描述符适用于当您想在变量中捕获标准输出但仍想写出到屏幕时,例如在 bash 脚本用户界面中

arg1 string to echo 
arg2 flag 0,1 print or not print to 3rd fd stdout descriptor   
function ecko3 {  
if [ "$2" -eq 1 ]; then 
    exec 3>$(tty) 
    echo -en "$1" | tee >(cat - >&3)
    exec 3>&- 
else 
    echo -en "$1"  
fi 
}
Run Code Online (Sandbox Code Playgroud)

  • 我知道这不是一个新的答案,但我不得不盯着这个很长一段时间看看它的作用,并认为如果有人添加了一个正在使用的函数的例子会有所帮助。这个回应并捕获了整个输出命令 - df,在这种情况下。https://dl.dropboxusercontent.com/u/54584985/mytest_redirect (2认同)

小智 5

这是使用附加文件描述符似乎合适的另一种情况(在 Bash 中):

命令行参数的Shell脚本密码安全

env -i bash --norc   # clean up environment
set +o history
read -s -p "Enter your password: " passwd
exec 3<<<"$passwd"
mycommand <&3  # cat /dev/stdin in mycommand
Run Code Online (Sandbox Code Playgroud)


归档时间:

查看次数:

55394 次

最近记录:

5 年,6 月 前