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まで待つ必要があります(validationを含む)。長期。なぜ私が望むファイルがほぼ常にすぐに現れるのか分かりません。findtop

XYの問題を避けるために上記の数行を追加しました。同じ機能とより速い実行を提供するすべてが満足です。

答え1

これには2つの可能性があります。fzfファイルを選択したときに実際にシャットダウンがないか、ファイルを選択したときfindにシャットダウンがありませんfzf。後者の場合は、find終了時に手動で閉じるスクリプトを作成できます。fzf

Linuxでパイプがどのように機能するかは、findパイプに書き込もうとし、失敗するまでパイプがパイプから何も読み取らないことを知りません。だからファイルを選択すると後ろに find探しているものがすべて見つかった場合、findパイプへの書き込みは行われなくなり、終了する前にファイルシステム全体が繰り返されます。

たとえば、任意のファイルを作成して/実行すると、find / -name $random_file_name | head -n 1非常に迅速に取得できるすべての出力が得られますが、プログラムは長時間実行され続けます。

この問題を解決する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を管理しなければならないというのが欠点ですね。バッシュとcoprocFIFOの名前を指定しなくても問題を解決できます。

(注:この回答が特定の問題ではなく一般的な問題を解決できるようにするために、変数と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'

関連情報