1

コマンドの進行状況を bash スクリプトで表示しています。コマンド出力は zenity --progress にパイプされ、最終的に長時間実行できます。Zenityダイアログをキャンセルした場合、それを中止(そのコマンドを強制終了)したい:

( echo 0; command; echo 100 ) | if ! zenity --progress
                                then DO_SOMETHING_TO_KILL_command
                                fi

私が見つけたすべての解決策は次のいずれかです。

  1. 一般的に、pgrep、pidof、pkill、killall などを使用して「コマンド」を強制終了します。このような「コマンド」が多数実行されている可能性があるため、これは私が望んでいるものではありません。

  2. 「コマンド」の PID を出力する fifo を作成し (command & echo $! >some_fifo; wait)、パイプの後に読み取ります。

解決策 2. は、私が望むことを行いますが、複雑すぎる方法です (たとえば、こちらの例を参照してください(フランス語))。可能であれば、fifos または一時ファイルを避けたいと考えています。せいぜいファイル記述子への出力リダイレクトで実行できるように思えますが、正確な方法はわかりません。

注: リダイレクトを使用したグループ全体のコマンド置換 (例: $( ( ... command& echo >&3 ... | zenity --progress ) 3>&1 ) -- これは、このタイプの場合の一般的なソリューションです -- $(...) はサブシェル全体が完了するまで待機するため、ここでは機能しません。

4

3 に答える 3

1

最も堅牢な実装の 1 つ:

#!/bin/bash

( # the pipe creates an implicit subshell; marking it explicit
 (
  sleep 10 & echo $! >&3
  wait
  echo 100 # to stdout, first pipe
 ) | (
  if ! zenity --progress
  then echo zen_progress_aborted >&3
  fi
 )
) 3>&1 | (
      read FD3_FIRST
      read FD3_SECOND
      # the PID comes first and the zenity output second almost always
      #+but we cannot be sure so:
      if [ "$FD3_SECOND" = "zen_progress_aborted" ]
       then kill $FD3_FIRST
      elif [ "$FD3_FIRST" = "zen_progress_aborted" ]
       then kill $FD3_SECOND
      fi
     )
# 'echo 100' after 'wait' means zenity does not exit after the command ends
#+so no need to kill it in this case

exit 0

「coproc」を使用するよりもかなり複雑ですが、POSIX 移植可能であり、2 番目の「echo」が最初のエコーを追い越すというまれなケースでは堅牢です (たとえば、バグのために zenity が失敗し、サブプロセスがたまたま後で開始される)。

于 2013-03-07T17:02:41.673 に答える
0

これはうまくいくはずです:

coproc { echo 0; command; echo 100; }
zenity --progress <&${COPROC[0]} || kill $!
于 2013-03-07T12:39:26.177 に答える