4

I have written a fairly simple script here that is meant to display a text info dialog using zenity and continuously read data from a remote TCP connection and display it in the dialog. This works... However I would like for the entire script to terminate if I close the zenity dialog.

Is there a way to do this? I don't think I can check for anything in the while loop, because the script could be stalled on reading the data from the remote TCP connection.

#!/bin/bash

on_exit() {
        zenity --display=:0 --error --text="Script has exited." &
}

# Options
while getopts "a:p:t:" OPTION; do case "$OPTION" in
        a) address="$OPTARG";;
        p) port="$OPTARG";;
        t) title="$OPTARG";;
esac; done

exec &> >(zenity --display=:0 --text-info --title=$title || exit)
                               # doesn't make a difference?  ↑
                               # also tried &&
trap "on_exit" EXIT

while read data < /dev/tcp/$address/$port; do
        echo $data
        # ...
        # do some other stuff with the information
        # ...
done

Note: This is going to be run on IGEL Linux. I don't have the option of installing additional packages. So, ideally the solution I'm looking for is native to Bash.


Update

I only had to make this modification to continue using exec. Or @BachLien's answer using named pipes also works.

PID=$$
exec &> >(zenity --display=:0 --text-info --title=$title; kill $PID)
Drew Chapin
  • 7,779
  • 5
  • 58
  • 84
  • Is it possible to put Zenity execution in a wrapper that waits for its termination and kills the target script afterwards? – hidefromkgb Feb 09 '18 at 17:59
  • Calling `exit` inside `>(...)` means exiting the subshell. You need to `kill` the parrent PID to terminate the parrent shell. Please consider to use named pipe (no need to install anything extra I believe) for easier coding. – Bach Lien Feb 09 '18 at 19:54

2 Answers2

1

I do not have zenity installed, so I tried this script to illustrate the idea.

The program terminal+cat (emmulating zenity) is executed by the function _dspMsg which runs in background (child process); cat continuously displays messages from a file ($m) which is a named pipe; the parent process is killed when terminal+cat exits.

In the mean while, another cat proccess writes messsages into pipe $m (emmulating TPC infomation feeds); it would be killed when when _dspMsg exits.

#!/bin/bash
                              # 1) named pipe
m=`mktemp -u /tmp/msg-XXXX=`  #    get a temporary filename (for named pipe)
mkfifo "$m"                   #    create that named pipe
trap "echo END; rm $m" EXIT   #    remove that file when exit
                              # 2) zenity
_dspMsg(){                    #    continuously display messages
  urxvt -e bash -c "cat <$m"  #    terminal+cat is used in place of zenity
  kill $1                     #    kill parent pid
}                             #    to be run in background
_dspMsg $$ &                  #    $$ = proccess id
                              # 3) TCP info feeds
cat >>"$m"                    #    feeding messages using cat
                              #    cat is used in placed of TCP data feed

Note:

  1. A named pipe is used as a way of communicating between parent and child processes.
  2. To test that script, you may need to change urxvt to xterm, iTerm, or any other terminal emmulator available in your computer.

So, maybe it is what you need (untested):

#!/bin/bash

while getopts "a:p:t:" OPTION; do case "$OPTION" in
  a) address="$OPTARG";;
  p) port="$OPTARG";;
  t) title="$OPTARG";;
esac; done

m=`mktemp -u /tmp/msg-XXXX=`
mkfifo "$m"
trap "zenity --display=:0 --error --text='Script has exited.' & rm $m" EXIT

_dspMsg(){
  zenity --display=:0 --text-info --title="$title" <"$m"
  kill $1
}

_dspMsg $$ &

while read data < /dev/tcp/$address/$port; do
  echo $data >>"$m"
done
Bach Lien
  • 1,030
  • 6
  • 7
  • This looks promising! `$$` is new to me. I didn't know there was such a way to get the PID current script. I will have to try it Monday though. Time is up for today. – Drew Chapin Feb 09 '18 at 21:09
0

You can pipe all of the output of the while loop into zenity, getting rid of the need for exec &>.

while read data < "/dev/tcp/$address/$port"; do
        echo "$data"
done | zenity --display=:0 --text-info --title="$title"
John Kugelman
  • 349,597
  • 67
  • 533
  • 578