TCL中的FIFO文件

TCL中的FIFO文件,tcl,freeze,fifo,mkfifo,gunzip,Tcl,Freeze,Fifo,Mkfifo,Gunzip,我需要在命名管道中解压文件并返回它: proc unzip_file_if_needed { fileName } { if { [file extension $fileName] != ".gz" } { return $fileName; } set tmpDir [fileutil::tempdir] set tmpFileName [ file join $tmpDir [ pid ] ] if { [file exists $t

我需要在命名管道中解压文件并返回它:

proc unzip_file_if_needed { fileName } {
    if { [file extension $fileName] != ".gz" } {
        return $fileName;
    }
    set tmpDir [fileutil::tempdir]
    set tmpFileName [ file join $tmpDir [ pid ] ]
    if { [file exists $tmpFileName ] } {
        file delete $tmpFileName
    }
    exec mkfifo $tmpFileName
    exec gunzip -c $fileName > $tmpFileName &
    return $tmpFileName
}
它挂在墙上
exec gunzip-c$fileName>$tmpFileName&

问题是,内核将在
open()
系统调用中阻塞,直到fifo向相反方向打开,而Tcl在分叉之前在父进程中创建重定向(因为这允许在正常情况下进行更可靠的错误处理). 您需要的是将
O_NONBLOCK
标志传递到
open()
syscall中,但是
exec
命令不能让您控制它。所以需要一些诡计

set fd [open $tmpFileName {WRONLY NONBLOCK}]
exec gunzip -c $fileName >@$fd &
close $fd

这是通过使用我们想要的标志手动执行
open
(Tcl将它们映射到中,而不使用
O_
前缀),然后将该描述符传递给子流程来实现的。请注意,由于这是我们正在设置的管道的写入端,我们必须在
WRONLY
模式下打开(这是
open…w
在封面下所做的,减去一些不适用于此处的标志,再加上
非块
,这是我们想要的魔法)。

我用这种方式解决了这个问题:

proc unzip_file_if_needed { fileName } {
    if { [file extension $fileName] != ".gz" } {
        return $fileName;
    }
    set tmpDir [fileutil::tempdir]
    set pId [pid]
    set tmpFileName [ file join $tmpDir pId ]
    set unzipCmd [ file join $tmpDir [ append pId "cmd.sh" ] ]
    if { [file exists $tmpFileName ] } {
        file delete $tmpFileName
    }

    if { [file exists $unzipCmd ] } {
        file delete $unzipCmd
    }

    set cmdDesc [open $unzipCmd { CREAT EXCL RDWR} 0777]
    puts $cmdDesc "\#!\/bin\/bash\n gunzip -c \$1 > \$2"
    close $cmdDesc

    exec mkfifo $tmpFileName
    exec $unzipCmd $fileName $tmpFileName >&@1 &

    return $tmpFileName
}

根据,这样的文件需要同时打开以进行读写。这意味着需要有人读取您解压缩到其中的数据。有人读了你解压到mkfifo文件中的内容吗?是的,它将在函数调用后被读取,这就是gunzip在后台执行的原因。它报告了一个错误:无法打开“/tmp/52977”:没有这样的设备或地址?