环境: GNU bash,版本 3.2.57(1)-release (x86_64-apple-darwin20)
尝试0:
exec 3<> "$(mktemp)" # open file descriptor 3 to a temp file for read/write
echo 'foo' >&3 # write 'foo' to descriptor 3
read bar <&3 # read contents of descriptor 3 to variable named bar (not using -u 3)
echo $? # exit status returns "1"
exec 3>&- # close file descriptor 3
在上面的代码片段中,我希望$bar
设置为"foo"
但它不起作用,因为文件描述符 3 中的位置位于文件描述符文件的末尾。
尝试1:
exec 3<> "$(mktemp)" # open file descriptor 3 to a temp file for read/write
echo 'foo' >&3 # write 'foo' to descriptor 3
cat <&3 # echo contents of of descriptor 3 to STDOUT
echo $? # exit status returns "0"
exec 3>&- # close file descriptor 3
这也失败了,因为描述符 3 中的文件位置位于末尾。
在 C/C++ 中,您可以rewind(...) 和 fseek(...)将创建的文件临时文件的文件指针重置到文件mktemp
的开头。
此处已知的解决方法:(使用第二个描述符)
myTempFile="$(mktemp)" # create temp file and assign to $myTempFile
exec 3> "$myTempFile" # open file descriptor 3 for writing to $myTempFile
exec 4< "$myTempFile" # open file descriptor 4 for reading of $myTempFile
echo 'foo' >&3 # write 'foo' to descriptor 3
read bar <&4 # read contents of descriptor 4 to variable named bar
echo $? # exit status returns "0"
echo "$bar" # echo "foo"
exec 3>&- # close file descriptor 3
exec 4>&- # close file descriptor 4
问题™(最终):
如何在 bash 中回退文件描述符而不使用第二个文件描述符从头开始读取?
注意:我不想安装ksh93来使用它的倒带功能。
exec 3<> "$(mktemp)"
echo 'foo' >&3
# Magic Happens here
read bar <&3 # expect $bar == "foo"
echo $? # expect "0"
exec 3>&-
虽然这是一个有趣的问题(但也是我 30 年来从未需要用外壳做的事情)。您可能正在尝试使用错误的工具。
Unix(UNIX、BSD、MacOS、Gnu/Linux)有管道。管道是一个特殊的文件(不在二级存储/磁盘中),它有两个文件描述符。一种用于写作,一种用于阅读。读描述符总是跟在写之后。读完数据后就废掉了。
有时您无法在启动命令时创建管道。在这些情况下,您可以使用命名管道或 unix-sockets。
使用其中一个进程创建和销毁一个 unix-socket。这也是两种方式。
可以独立于两个进程创建命名管道。
zsh
并且ksh93
具有系统调用的内置包装器lseek()
,但没有 bash,因此您需要调用一个单独的实用程序,该实用程序可以对附加到 fdlseek()
的打开文件描述执行zsh
默认情况下安装在 macos 上,因此,如果您必须使用bash
,您可以定义一个包装的内置sysseek
函数:zsh
sysseek
并使用:
将 fd 3 倒回到开头。
没有系统的另一种选择
zsh
是使用perl
更广泛可用的系统:并使用:
将 fd 3 倒回到开头。
第二个参数可以是:
sysseek -w start
inzsh
,默认存在)。zsh
'ssysseek -w current
)寻找zsh
'ssysseek -w end
) 查找。将读取描述符的创建与写入描述符分开:
3 描述符的表被覆盖,变为只读。使用通用描述符是没有意义的。
在变量中隐藏描述符编号:
由于首先执行重定向,因此
$fd
变量被写入并且在块内已经有一个值。这里需要注意的是,句柄不会像 ksh93 中那样自动关闭,必须显式关闭,在块的末尾或使用下一个命令(显示两个选项)。准备在下一个 bash 版本中引入一个内置变量,可以将其更改为自动关闭行为。使用这种形式的调用,不需要命令exec {fd}<&-