web-dev-qa-db-ja.com

bashがユーザーからの入力を要求したときに通知またはアラートを送信する

Ubuntu 16.04 LTSを使用しています。私の.bashrcには、notify-sendを使用するエイリアスがあります。

alias alert='notify-send --urgency=low -i "$([ $? = 0 ] && echo terminal || echo error)" "$(history|tail -n1|sed -e '\''s/^\s*[0-9]\+\s*//;s/[;&|]\s*alert$//'\'')"'

alertsomecommand; alertまたはsomecommand && alertとして他のコマンドに追加し、somecommandが完了した(成功した)後にポップアップ通知を取得できます。最小化されたターミナルウィンドウまたは別のワークスペースで実行したコマンドの実行が終了したことを思い出します。

しかし、完了ではなくユーザーからの入力を待機するときに同様のアラートが必要です(たとえば、はい/いいえプロンプト)。どうやってやるの?

notify-sendを使用した類似のソリューションは素晴らしいですが、他の比較的単純の代替案も問題ありません。

混乱がある場合は、プロンプトへの自動返信を作成する予定はありません。ユーザー入力を要求する可能性のある長い出力(例:apt update && apt upgrade)でコマンドを実行しているときに、忘れられた(最小化された/別のワークスペースにある)ターミナルウィンドウを思い出させるだけです。

3
pomsky

プログラムの対話を監視し、アラートを送信する

あなたはの活動を監視することができます

  1. afifoまたは
  2. xtermログファイル、インタラクティブモードになりました

監視対象プログラムからの入力があると、zenity情報メッセージを開始させます。必要に応じて、espeakをインストールして、オーディオメッセージを送信することもできます

1. fifoを使用して監視対象プログラムからの入力がある場合、zenity情報メッセージを開始します。

次のシェルスクリプトは、プログラムからの出力ダイアログを監視し、アラートを送信できます。

  • グラフィカルデスクトップ環境を想定
  • ターミナルウィンドウでラッパーシェルスクリプトを開始します。これはwrapperの「コンソール」のように使用されます
  • 監視するプログラムをxtermウィンドウで開始する
  • xtermウィンドウでダイアログを実行する(ここに入力を書き込みます)
  • fifoを使用して、監視するプログラムの出力/dev/stdoutおよびdev/stderrにアクセスします。
  • whileループの実行
    • fifoが変更されているかどうかをテストし、その場合
      • zenity情報メッセージウィンドウを開始しています。

入力を書き込むzenityウィンドウに戻るには、xtermウィンドウ(「Enter」キーで操作できます)を閉じる必要があります。

#!/bin/bash

if [ $# -eq 0 ]
then
 echo "'$0' is a wrapper, that sends a notification, when the wrapped program
has written to standard input and standard error and may be waiting for input.
---
Usage:   $0 <program name> [parameters]
Example: $0 .program"
 exit
fi

message="'${1##*/} $2 ...' has written something, maybe asks for input"

tmpdir=$(mktemp -d)
tmpfifo=$(mktemp --tmpdir=$tmpdir)
rm "$tmpfifo"
mkfifo "$tmpfifo"
#ls -l "$tmpdir"
cnt1=$(stat --printf "%Y" "$tmpfifo")
sleep 1

xterm -title "${1##*/} $2 ..." -fa default -fs 11 -bg '#403600' \
 -e bash -c "$* 2>&1 | tee /dev/stderr 2>&1 > $tmpfifo" 2> /dev/null & pid=$!

#< "$tmpfifo" espeak &
< "$tmpfifo" cat &

cont=true
while $cont
do
 tmpstr=$(ps -Af |sed "s/grep $pid//"|grep "$pid")
# echo "$tmpstr"
 if [ "$tmpstr" != "" ]
 then
  cnt0=$cnt1
  cnt1=$(stat --printf "%Y" "$tmpfifo")
  if [ "$cnt1" != "$cnt0" ]
  then
#   zenity --notification --text="$message" 2> /dev/null
#   espeak "$message" &
   zenity --info --title="${0##*/} ${1##*/} $2 ..." \
    --text="$message" --width=500  2> /dev/null
  fi
  sleep 1
  else
  sleep .2
  # echo "process $pid has finished"
  cont=false
 fi
done

# clean up

rm -r "$tmpdir"

espeakの近くでzenityを実行して、音声メッセージを取得することもできます。その場合、その行の先頭にある#文字を削除できます。 (プログラムからのテキストが多い可能性があるため、通常はfifoをespeakにリダイレクトすることはお勧めしません。fifoをcatにリダイレクトして印刷することをお勧めします「コンソール」。)

デモ

cp -iおよびmv -iを使用していくつかのコマンドラインをテストできます。また、次の小さなシェルスクリプトprogramを使用してテストできます。

#!/bin/bash

while true
do
 read -p "Waiting for input. 'Stop' to Quit " string
 if [ "${string:0:4}" == "Stop" ]
 then
  printf "$string. Gotcha\n"
  break
 Elif [ "$string" != "" ]
 then
  printf "$string\n"
  printf "Working for 10 seconds ...\n"
  sleep 10
 else 
  sleep 3
 fi
done

ヘルプテキスト:

$ ./wrapper
'./wrapper' is a wrapper, that sends a notification, when the wrapped program
has written to standard input and standard error and may be waiting for input.
---
Usage:   ./wrapper <program name> [parameters]
Example: ./wrapper .program

モニタリングprogram

$ ./wrapper ./program

zenity情報メッセージウィンドウ:

enter image description here

xtermウィンドウでのダイアログ:

Waiting for input. 'Stop' to Quit Hello
Hello
Working for 10 seconds ...
Waiting for input. 'Stop' to Quit World
World
Working for 10 seconds ...
Waiting for input. 'Stop' to Quit Goodbye
Goodbye
Working for 10 seconds ...
Waiting for input. 'Stop' to Quit Stop

終了後の元のターミナルウィンドウの「コンソール」出力:

$ ./wrapper ./program
Waiting for input. 'Stop' to Quit Hello
Working for 10 seconds ...
Waiting for input. 'Stop' to Quit World
Working for 10 seconds ...
Waiting for input. 'Stop' to Quit Goodbye
Working for 10 seconds ...
Waiting for input. 'Stop' to Quit Stop. Gotcha

モニタリングcp -ip

$ LANG=C /path/wrapper cp -ip ubuntustudio-18.04-dvd-AMD64.iso ubuntu-18.04.1-desktop-AMD64.iso /tmp

zenity情報メッセージウィンドウ:

enter image description here

xtermでの対話:

cp: overwrite '/tmp/ubuntustudio-18.04-dvd-AMD64.iso'? y
cp: overwrite '/tmp/ubuntu-18.04.1-desktop-AMD64.iso'? n

モニタリングSudo parted /dev/sdc

$ LANG=C ./wrapper Sudo parted /dev/sdc

xtermでの対話:

[Sudo] password for sudodus: 
GNU Parted 3.2
Using /dev/sdc
Welcome to GNU Parted! Type 'help' to view a list of commands.
(parted) p                                                                
Model: SanDisk Extreme (scsi)
Disk /dev/sdc: 16,0GB
Sector size (logical/physical): 512B/512B
Partition Table: msdos
Disk Flags: 

Number  Start   End     Size    Type      File system  Flags
 3      2097kB  258MB   256MB   primary   fat32        boot
 4      258MB   1366MB  1108MB  primary
 2      1366MB  12,4GB  11,0GB  extended               lba
 5      1367MB  6736MB  5369MB  logical   ext2
 6      6737MB  12,4GB  5615MB  logical   ext4
 1      12,4GB  16,0GB  3662MB  primary   ntfs

(parted) q

2.(監視対象プログラムまたはユーザーから)zenityウィンドウに何かが書き込まれたときに、xterm情報メッセージを開始します。

次のシェルスクリプトは、プログラムとの対話を監視し、アラートを送信できます。

  • グラフィカルデスクトップ環境を想定
  • ターミナルウィンドウでラッパーシェルスクリプトを開始します。これはwrapperの「コンソール」のように使用されます
  • 監視するプログラムをxtermウィンドウで開始する
  • xtermウィンドウでダイアログを実行する(ここに入力を書き込みます)
  • xtermのログファイルを使用して、監視対象のプログラムからの出力および入力へのアクセスを取得する
  • whileループの実行
    • ログファイルが変更されているかどうかをテストし、その場合
      • zenity情報メッセージウィンドウを開始しています。
      • 入力の入力中に短い遅延が許可されます(8秒。スクリプトファイルを編集して遅延時間を変更できます)。

入力を書き込むzenityウィンドウに戻るには、xtermウィンドウ(「Enter」キーで操作できます)を閉じる必要があります。

これで、ターミナルウィンドウを使用するのと同じようにxtermウィンドウを使用するインタラクティブモードがあります。xterm監視を停止するウィンドウ。

#!/bin/bash

# date        editor   comment
# 2018-12-31  sudodus  version 1.0

version=1.0

name="${0##*/}"
if [ "$1" == "-h" ] || [ "$1" == "--help" ]
then
 echo "'$name' is a wrapper, that sends a notification, when the wrapped program
has written to standard input and standard error and may be waiting for input.
---
Usage:    $name [program name] [parameters]
Examples: $name          # to run program(s) interactively in an xterm window
          $name program
          $name -h       # to get help (this text)
          $name -v       # show version"
 exit
Elif [ "$1" == "-v" ]
then
 echo "$name version $version"
 exit
fi
tstart=$(date '+%s')
echo "----- start $name at $(date '+%F %T') ----------------------------"
tmpstr="${1##*/}"
xtermlog=$(mktemp -u)

if [ $# -eq 0 ]
then
 mess_zenity="Check, if the monitored program asks for input"
 mess_espeak="${mess_zenity/program/, Program,}"
 xterm -title "monitored by ${0##*/}" -fa default -fs 11 -bg '#2c2b2a' \
 -l -lf "$xtermlog" -sb -rightbar 2> /dev/null & pid=$!
else
 mess_espeak="Check if '${tmpstr^} ${2##*/} ${3##*/} ...' asks for input"
 mess_zenity="Check if '$tmpstr $2 $3 ...' asks for input"
 xterm -title "${1##*/} $2 $3 ..." -fa default -fs 11 -bg '#2c2b2a' \
 -l -lf "$xtermlog" -e "$@" 2> /dev/null & pid=$!
fi
sleep 0.5
sync
cnt1=$(stat --printf "%Y" "$xtermlog")
tail -f "$xtermlog" & ptail=$!

cont=true
while $cont
do
 sleep 1
 cnt0=$cnt1
 tmpstr=$(ps -Af |sed "s/grep $pid//"|grep "$pid")
# echo "$tmpstr"
 if [ "$tmpstr" != "" ]
 then
  cnt1=$(stat --printf "%Y" "$xtermlog")
  if [ $cnt1 -gt $((cnt0 + 8)) ]
  then
#   zenity --notification --text="$message" 2> /dev/null
   espeak "$mess_espeak" &
   zenity --info --title="${0##*/} ${1##*/} $2 ..." \
    --text="$mess_zenity" --width=500  2> /dev/null
   touch "$xtermlog"
   cnt1=$(stat --printf "%Y" "$xtermlog")
  fi
  sleep 1
  else
  sleep .2
  # echo "process $pid has finished"
  cont=false
 fi
done

# clean up
tmpstr="$(tail -n1 "$xtermlog" | sed 's/.*exit.*/exit/')"
if [ "$tmpstr" != "exit" ]
then
 echo ""
fi
rm -r "$xtermlog"
kill $ptail
tend=$(date '+%s')
tuse=$((tend-tstart))
echo "------- end $name at $(date '+%F %T') --- used $tuse seconds"

このbashコードをファイルに保存し、[例]にvialogという名前を付け、実行可能にして、パス内のディレクトリに移動します。

$ vialog
----- start vialog at 2018-12-31 14:37:41 ----------------------------

xtermウィンドウで作業すると、ダイアログが開始ウィンドウにもエコーされます。

enter image description here

sudodus@bionic64 /media/multimed-2/test/test0/pomsky-wrap $ ./program
Waiting for input. 'Stop' to Quit Hello World
Hello World
Working for 10 seconds ...
Waiting for input. 'Stop' to Quit I am writing ...
I am writing ...
Working for 10 seconds ...
Waiting for input. 'Stop' to Quit Stop
Stop. Gotcha
sudodus@bionic64 /media/multimed-2/test/test0/pomsky-wrap $ scrot -sb
sudodus@bionic64 /media/multimed-2/test/test0/pomsky-wrap $ exit
exit
------- end vialog at 2018-12-31 14:39:02 --- used 81 seconds

enter image description here

3
sudodus

フィードバックへの招待

私の既存の回答に別のシェルスクリプトを追加する代わりに、2番目の回答の方が良いと思います。私はフィードバックに耳を傾け、優先するスクリプト/メソッドに焦点を当て、(異なる目的で)すべてを保持する理由がない限り、優先するものを1つの回答にマージしようとします。

プログラムの対話を監視し、アラートを送信する

あなたはの活動を監視することができます

  1. afifoまたは
  2. xtermログファイル

監視対象プログラムからの入力があると、zenity情報メッセージを開始させます。必要に応じて、espeakをインストールして、オーディオメッセージを送信することもできます

この回答は、fifoを使用した2番目の選択肢に焦点を当てています。

Fifoを使用して監視対象プログラムからの入力があるときに、zenity情報メッセージを開始します。

1.1 xtermを使用して、FIFO経由で標準出力と標準エラーを監視する

このwrapperメソッドには

  • advantage、直接入力するとアラートがトリガーされないこと。これは、cp -iSudoなどの多くのプログラムでうまく機能します。
  • 欠点、それ
    • 一部のプログラムは、出力を書き込むために標準出力と標準エラーだけを使用するわけではないため、無効になります。例:sftpは、プログラムが新しいタスクの準備ができると、プロンプトを失い、ユーザーはそれを知ることができません。
    • 一部のプログラムは入力をエコーし​​ます(間接的な入力があります)。これによりアラートがトリガーされます。これにより、シェルスクリプトで多くのアラートが発生し、それが考慮されません。例:ssh

1.2コンパイルされたプログラムscriptとそのログファイルをfifo経由で使用する

次のシェルスクリプトは、プログラムからの出力ダイアログを監視し、アラートを送信できます。 espeakscriptが必要です(scriptはUbuntuとDebianにインストールする必要はありません)。

Sudo apt update
Sudo apt install espeak
  • グラフィカルデスクトップ環境を想定
  • ターミナルウィンドウでシェルスクリプトを開始し、viafifoと呼びます。
  • 監視対象のプログラムを「viafifo」で開始
  • ターミナルウィンドウでダイアログを実行する(ここに入力を書き込みます)
  • fifoを使用して、監視対象のプログラムの出力/dev/stdin/dev/stdoutおよびdev/stderrにアクセスします。シェルスクリプトの主なタスクは、プログラムscriptのある行です。これは、ターミナルウィンドウでアクティビティを監視し、 fifo。
  • whileループの実行
    • fifoが変更されているかどうかをテストし、その場合
      • zenity情報メッセージウィンドウと対応する音声メッセージをespeakで開始します。
      • 入力の入力中に短い遅延が許可されます(8秒。スクリプトファイルを編集して遅延時間を変更できます)。

入力を書き込むzenityウィンドウに戻るには、xtermウィンドウ(「Enter」キーで操作できます)を閉じる必要があります。

exitと入力してscriptviafifoを終了します。その後、ダイアログ全体のログファイルを取得できます。

viafifo

  • Ubuntu18.04.1 LTS<---このリンクviafifobashコードが見つかります。
  • Debian9.6.0、「ストレッチ」。次のスクリーンショットとtime viafifoviafifo.logの印刷を参照してください。

デモ例

スクリーンショット

enter image description here

enter image description here

time viafifo

user@debian:~$ time viafifo
----- Start viafifo ------------------------------------------------------------
user@debian:~$ echo hello
hello
user@debian:~$ exit
exit
----- End viafifo --------------------------------------------------------------
See 'viafifo.log'
viafifo used 8 seconds plus a few (5-10) seconds for preparing and finishing
real    0m13.295s
user    0m0.104s
sys 0m0.012s

viafifo.log

user@debian:~$ cat viafifo.log
Script started on Sat 05 Jan 2019 07:57:45 PM UTC
user@debian:~$ echo hello
hello
user@debian:~$ exit
exit
viafifo used 8 seconds
user@debian:~$ 
1
sudodus