我有以下 bash 脚本,我想将其用作模糊文件打开器。我创建一个 fifo,生成一个运行 fzf 的新终端,并将 fzf 的输出重定向到 fifo。然后我调用一个从 fifo 读取并打开文件的函数。
我的问题是函数内的 while 循环open
永远不会结束。读取所有行后如何关闭 fifo?
#!/usr/bin/env bash
FIFO=/tmp/fuzzy-opener
[ -e "$FIFO" ] || mkfifo "$FIFO"
exec 3<> "$FIFO"
function open {
while read file; do
# open every $file based on its mime-type
done <&3
echo 'done' # this is never reached
}
alacritty -e sh -c "fzf -m >&3" \
&& open
答案1
read()
如果写入端关闭,管道将显示 EOF(从零字节读取返回)。但我认为发生的情况是,既然<>
以读写模式打开管道,管道总是有一个写入器,外壳保持文件句柄打开。
我认为您应该能够跳过在外壳中打开管道,而只需执行以下操作:
alacritty -e sh -c "fzf -m >$FIFO" && open < "$FIFO"
或者更恰当地说:
alacritty -e sh -c 'fzf -m >"$1"' sh "$FIFO" && open < "$FIFO"
我在这里假设问题中的构造以其他方式工作,如果 alacritty 在后台生成一个终端并立即退出,则应该如此。如果没有,您需要alacritty -e sh ... & open < "$FIFO"
同时运行这两个部分。
答案2
我会建议几个替代方案,因为:
- 根据您问题中的脚本, FIFO 似乎实际上不需要;
- 原则上,由于您使用的是 Bash,因此您可以利用 NUL 字符作为分隔符(POSIX 文件路径中唯一不允许的字节);但不幸的是,它
fzf
似乎不适用于包含换行符的文件名; - 从文件中读取
/tmp
可能会造成重大安全问题:如果其他人创建了/tmp/fuzzy-opener
(作为常规文件),您的脚本将很乐意应用于open
其内容(尽管在某些系统上,在可字写的粘性文件中打开不拥有的文件)使用exec 3<>
will 的目录提出错误)。
您可以使用:
function open {
while IFS= read -r -d '' file
do
echo "$file" # Replace with the actual open action
done
}
alacritty -e sh -c 'fzf -m --disabled --print0 >&3' 3>&1 | open
-d ''
可以通过删除和使其变得可移植--print0
(考虑到上述限制,不会丢失任何内容fzf
);或者,使用数组来存储选定的文件名:
function open {
for file
do
echo "$file" # Replace with the actual open action
done
}
mapfile -t -d '' toopen < <(alacritty -e sh -c 'fzf -m --print0 >&3' 3>&1) &&
open "${toopen[@]}"
在这两种情况下,要点是fzf
的输出被重定向到一个新的文件描述符,该文件描述符是通过复制管道的写入端而获得的,从而连接到读取器命令。