Bash:如果接收其输出的进程终止,如何杀死 eval

Bash:如果接收其输出的进程终止,如何杀死 eval

我的 Ubuntu 机器上有一个丑陋的 bash 脚本,其中包含以下行:

search_command="find -L $(printf "%q" "$search_folder") \( ! -regex '.*/\..*/..*' \) -mindepth 1 2> /dev/null"
for i in "${IGNOREENDINGS[@]}"
do
    search_command="$search_command -not -name \"*$i\""
done
search_command="$search_command | sed 's|^${search_folder}/\?||'"
choice=$(eval "$search_command"|fzf -q "$file_query" -1 --preview "preview $search_folder {}")

fzf该脚本允许我使用命令的匹配项来选择一个文件GNU find

它有以下问题:一旦我在脚本界面中选择一个文件,fzf就会关闭 fzf 界面,这样似乎就完成了,但我仍然必须等待命令find完成(用 验证top),这不知何故需要很长时间长的。我不太确定为什么;我想要的文件几乎总是立即出现。

我在上面添加了一些额外的行以避免 XY 问题。我对具有相同功能和更快执行速度的任何东西都很满意。

答案1

这里有两种可能性:要么fzf在选择文件时实际上没有退出,要么在选择文件find时没有退出fzf。如果是后者,可以写一个脚本,退出find时手动关闭。fzf

Linux 中管道的工作方式find并不知道它正在写入的管道没有从该管道读取任何内容,直到它尝试写入该管道并失败为止。因此,如果您选择该文件 find已经找到了它要找到的所有内容,find不再写入管道,因此将在退出之前迭代整个文件系统。

举例来说,如果您在中创建一个随机文件/然后运行find / -name $random_file_name | head -n 1,您将很快获得您将获得的所有输出,但程序将继续运行很长时间。

解决这个问题的一种方法是在进程完成后自行终止该进程。在您的具体情况下,最简单的方法可能是命名管道:

tmp_fifo=`mktemp -u`
mkfifo "$tmp_fifo"
eval "$search_command" > "$tmp_fifo" &
choice="$(fzf -q "$file_query" -1 --preview "preview $search_folder {}" < "$tmp_fifo")" ; kill $!
rm "$tmp_fifo"

这将创建一个临时命名管道,find对其进行写入和fzf读取。但是fzf退出时,kill $!运行,其中$!代表最后一个启动的后台进程,在本例中为find

答案2

另一个答案看起来不错,缺点是你需要管理 fifo。与 Bash 的coproc您可以在没有命名 fifo 的情况下解决问题。

(注意:为了使这个答案解决一般问题而不是您的具体问题,我删除了您的变量eval和类似的东西)。

coproc find ...         # this silently runs in background, no `&' nor explicit redirection needed
<&${COPROC[0]} fzf ...  # piping from `find' to `fzf'
kill $!                 # killing the last background process, i.e. `find'

相关内容