如何在 bash 中倒帶文件描述符而不使用第二個文件描述符從 bash for Mac 的開頭讀取?
環境: 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)有管道。管道是一個特殊的文件(不在二級儲存/磁碟中),它有兩個文件描述符。一種用於寫作,一種用於閱讀。讀描述符總是跟在寫之後。讀完數據後就廢掉了。
echo a_command | another_command
有時您無法在啟動命令時創建管道。在這些情況下,您可以使用命名管道或 unix-sockets。
使用其中一個程序創建和銷毀一個 unix-socket。這也是兩種方式。
可以獨立於兩個程序創建命名管道。
zsh
並且ksh93
具有系統呼叫的內置包裝器lseek()
,但沒有 bash,因此您需要呼叫一個單獨的實用程序,該實用程序可以對附加到 fdlseek()
的打開文件描述執行zsh
預設情況下安裝在 macos 上,因此,如果您必須使用bash
,您可以定義一個包裝的內置sysseek
函式:zsh``sysseek
sysseek() { zsh -c ' zmodload zsh/system sysseek "$@" || syserror -p "$0: " ' sysseek "$@" }
並使用:
sysseek -u 3 0
將 fd 3 倒回到開頭。
沒有系統的另一種選擇
zsh
是使用perl
更廣泛可用的系統:sysseek() { # args: fd, mode, offset perl -e ' my ($fd, $mode, $offset) = @ARGV; open FD, ">&", $fd or die "fd $fd: $!\n"; seek FD, $mode, $offset or die "seek: $!\n"; ' -- "$@" }
並使用:
sysseek 3 0 0
將 fd 3 倒回到開頭。
第二個參數可以是:
- seek 相對於開始(如
sysseek -w start
inzsh
,預設存在)。- 相對於目前位置 (
zsh
’ssysseek -w current
)尋找- 相對於文件末尾 (
zsh
’ssysseek -w end
) 查找。