Over a million developers have joined DZone.

A Rabbit Trail: Menu-Driven Bash Script -Part IV

Today we'll be separating the mysqld output that currently clutters the main menu window, by starting up the mysqld in a separate, child window. We'll look into creating windows, sizing them, and using color to give context.

· Web Dev Zone

Start coding today to experience the powerful engine that drives data application’s development, brought to you in partnership with Qlik.

Introduction

In Part 3 of "A Rabbit Trail", we improved our in-house tool that we will be adding to bit by bit, as we use it to help us with our main Web App / Web Services projects.

We added the ability to handle a rather ungraceful event such as a CTRL-C, and properly shutdown the MySQL database, instead of the script exiting, and crashing the database server.

We did this with job control and trapping the SIGINT signal.

If you're interested in the main Web Apps / Web Services projects-track, you can check out the complete article series.

This article's main point today is: separating the mysqld output that currently clutters the main menu window, by starting up the mysqld in a separate, child window.  We'll look into creating windows, sizing them, and using color to give context.

Please see Part 1, for some help on installing Cygwin.  (That's not the main point of these articles).

MINTTY

Let's begin by familiarizing ourselves with this nice little terminal emulator for Cygwin.

Open a new Cygwin window.   I can start mine via a desktop shortcut, and I also have it pinned to the taskbar:

Image title

Once opened,  make it small so you can see most of the screen:

Image title

Now, type a  mintty <ENTER> at the $ prompt in that window:

Image title

Upon hitting <ENTER>, you should see another, new Cygwin window pop up on the desktop:

Image title

My second window was just as big as the first one before I shrunk it.

Let's try to tackle:

  • making both windows usable

  • giving the child window a title (like "MYSQLD")

  • adding a distinguishing color

  • remembering the window size and postion for next time

  • making sure child window exits,  if parent window is exiting

Making Both Windows Usable

This one is pretty easy.   Just  do an   exit <ENTER>   in the child window (it disappears), and you're back at a usuable  $  prompt in the parent window (where you had entered mintty ).

Recall the original mintty command by hitting the up-arrow key.  But this time, before hitting <ENTER> , add an  & (ampersand) at the end.   If you have followed the previous article, you know this runs the command in the background, and that is what frees up your parent window to be interactive.

Image title

Add A Window Title

Exit from child window again.  By the way, you can clear the parent screen by entering clear .

Recall the  mintty &   line again, but first add a title, like so:  mintty -T MYSQLD & 

Image title

Change Window Color

This can be done several ways.

One way is to have an external config file.

Another way is to do it programmatically inside a script.

Still another way is to specify it on the command line.

Here is the command line way of doing it.   We're going to create a child MYSQL-titled window with yellow font (mostly), and a bluish background, and we're going to run it on  its own, leaving the parent window interactive:

Image title

Do not let the way the starting command looks throw you:

 mintty \
-T MYSQL \
-o ForegroundColour=255,255,0 \
-o BackgroundColour=0,0,80 \
&

The "\" (backslash) tells the shell that the command input continues on the next line.  I wrote it that way so the image would fit in this article.

We will take a look at changing the color via a script later, when we actually start working with a script.

Window Size and Position

You probably might be getting tired of resizing the windows.  I certainly am, because my original default settings make the windows take up most of my screen.  In any case, as this tool develops into something, you may find you like certain windows in certain areas of the screen, and a certain size.

We could begin by just specifying the position and size of the child window on the command line as an option.  However, I want it to be smarter and better than that.  I want the main window (our main script) to know, and remember, the child window's size and position.

What we want is to be able to make it smaller and move it:

Image title

Reporting Size And Position

In order to do what we want, we need to be told by the child window what its new settings are. Let's ask the child window to "report" back to the main/parent window, what its settings were upon its exit. This is done with the  -R , or the --Reportpos(mode)  option. Let's add this to our ongoing command.

Copy-paste this into main (black) window:

 mintty \
-T MYSQL \
-o ForegroundColour=255,255,0 \
-o BackgroundColour=0,0,80 \
-R s \
&

Then  hit <ENTER> :Image title

We run that command with the new reporting option.  That creates the blue child window. When we  exit  from the child window, the parent window will show some new information that is output by the child window upon its demise:

Image title

Capturing Window Size / Position

Keep in mind that we are going to eventually be creating this child MYSQL window from within our main Bash script (articles Part 1 and Part 2). We need to somehow grab the above result (the size / position report text) and then use it when the main script goes to create the child window the next time. The wrinkle that we have is that we will be starting off the child window in the background, meaning that our main script will have "moved on". Let's demonstrate what we're doing here, the simplest way (NOT moving on; NOT doing child window in background).

First, here's what my Cywin  $HOME/<user>  directory currently contains:

Image title

Then I create a child window with the following.  Notice I have redirected any console output that the mintty command would have, to a file called mintty-report.txt:

mintty \
-T MYSQL \
-o ForegroundColour=255,255,0 \
-o BackgroundColour=0,0,80 \
-s 40,15 -p 300,200 \
-R s > mintty-report.txt

And then I move , resize the child window:

Image title

Image title

Then I exit the child window, and let's do another listing of the home directory, using the main window:

Image title

We have a new file created in the directory.  Let's see what it contains:

Image title

Notice that when we created the child with mintty, the original settings were:

 -s 40, 15 -p 300,200 

but when we moved the child, the report file contains:

 -s 15,6 -p 169,70 

We can use that file information (later)  for our next child-window creation.

There's another way to do this, without resorting to a file.  Let's use a Bash variable, as if we were writing a script:

report=$(mintty \
-T MYSQL \
-o ForegroundColour=255,255,0 \
-o BackgroundColour=0,0,80 \
-s 40,15 -p 300,200 \
-R s);

echo;echo "child reports: $report";

We do the same thing (move and resize child window, then exit), and here are the results in the main parent window:

Image title

Did you notice that we didn't get the report back in the main window until we exited the child window?  Because we didn't run this in the background.  Let's do that next.

Remember I mentioned a wrinkle.

If we try placing the  &  (ampersand) within the  $(...),  then we notice that the parent window is not responsive.  And we still do not get the report until AFTER we exit the child window.

If we place the  &  outside, like so:   $(...) & ,  that doesn't work either.

It does not appear we can use a Bash variable in this case.  So we'll go with the file method.

Using Captured Window Info On Next Window Creation

Here, then, is a basic script that:

  • creates a blue child MYSQL window,

  • then the main script loops, prints out something to the main screen (to show it's interactive),

  • while we move/size the child window to somewhere else on the screen

  • then when we exit the blue window (at new size / position)

  • the main window script grabs values and creates a green window at same size / position

Exit all your Cygwin windows, then start up a new one, and paste copy-paste the following script into it:

########################################
# 'pound' or 'hash' is a comment
# lets make sure file does NOT exist
########################################
rm reportpos.txt;

########################################
# create MYSQL window with orig size/pos
# it will run on its own
########################################
mintty \
-T MYSQL \
-o ForegroundColour=255,255,0 \
-o BackgroundColour=0,0,80 \
-s 40,15 -p 300,200 \
-R s > reportpos.txt &


########################################
# we need the child's process id to track it
########################################
CHILD=$!;

########################################
# loop til blue MYSQL window exits
########################################
while [ 1 ]; do echo "Main Window pretending to do something"; echo "until you exit MYSQL window"; echo; is_child=$(ps -ef | grep $CHILD); if [ "$is_child" = "" ]; then break; fi; sleep 2; done;

echo;
echo;
echo "You exited the MYSQL window";

########################################
# use file info as new size / position
# 'sed' command will remove 'mintty'
# from the file info, leaving only
# size and position,
# all of that, assigned to a variable.
########################################
size_n_position=$(cat reportpos.txt | sed 's/mintty//');

echo;
echo "the NEW size and position : $size_n_position";


########################################
# create green MYSQL window with NEW size/pos
# it will run on its own
########################################
mintty \
-T MYSQL \
-o ForegroundColour=255,255,0 \
-o BackgroundColour=0,80,0 \
$size_n_position &

Controlling Child Window(s)

Ok, we have covered most of the bullet-points from the start of this article.   We are at the last one.

Remember that when we started,  the main (black) window was NON-interactive until we exited the child (blue) window.

Then we learned to run the blue window in the background, and that made the main window interactive again.   Let's repeat this, and we're going to try something different, to expose a problem.

mintty \
-T MYSQL \
-o ForegroundColour=255,255,0 \
-o BackgroundColour=0,0,80 \
-s 40,15 -p 300,200 \
-R s > reportpos.txt &

Copy-paste the above into the main window and  hit <ENTER>But this time, enter  exit  in the main black window, NOT the blue child window. What happened? The main window is gone, and the child window is still there. This may, or may not, be a problem, depending on your needs.

But consider the case where our menu-driven tool (articles Part 1 and Part 2), eventually creates several windows.   With the above problem, exiting the menu doesn't remove all the spawned windows.    AND - it's a pain to have to individually close all the child windows, one by one. It would be nice if the main menu window handled that for us.

Try the following script.  First, close all Cygwin windows.   Then start a new one.  Make it small enough and put it in some corner.  Then copy-paste the following.  I had to break it up into two parts to copy-paste, because all this time, we have been acting like we are running a script, when in fact we have an interactive window, and they're not 100% the same thing.

The following script will:

  • create 3 windows (blue, red, green), and staggered.

  • main script will loop with 1 sec delay, prompting you to enter a 'Q' whenever you wish

  • go ahead an enter a 'Q'.

mintty \
-T MYSQL_1 \
-o ForegroundColour=255,255,0 \
-o BackgroundColour=0,0,80 \
-s 40,15 -p 300,200 &
CHILD_1=$!

mintty \
-T MYSQL_2 \
-o ForegroundColour=255,255,0 \
-o BackgroundColour=0,80,0 \
-s 40,15 -p 350,250 &
CHILD_2=$!

mintty \
-T MYSQL_3 \
-o ForegroundColour=255,255,0 \
-o BackgroundColour=80,0,0 \
-s 40,15 -p 400,300 &
CHILD_3=$!

while [ 1 ];
do
echo;
read -t 1 -p "Main Window Loops Until You enter a 'Q' : " user_input;
if [ "$user_input" = "Q" ];
then
break;
fi;
done;


Image title

Image title

Now, if we had been running a REAL script, what is next would have automatically taken place as soon as you entered the 'Q' to quit loop.   The following remainder of the script handles termination of the three child windows:


echo;
echo "Terminating $CHILD_1  $CHILD_2 $CHILD_3 ";

kill -2 $CHILD_1  $CHILD_2 $CHILD_3 ;
wait;

So we copy-paste this into the main (black) window, and voila!  The other windows disappear.

The last question is:  What is the  wait  for?

Assume that each child window was actually  doing something.   For instance, one is running MySQL server.  Who knows, maybe the other was conducting some kind of test in a loop, maybe hitting some URL. Whatever.

The wait ensures that the parent window doesn't go away until all the children are done. This can come in handy if we add CTRL-C handling in the main script, and it can maybe try other things to kill those children.

Latest Code

You can try all this out with our latest scripts.

Main script,  my-tools.sh  is here.

Script that runs in child window,  my-tools-run-mysql-in-window.sh  is here.

Place those two script files in your local Cygwin directory.

Image title


Image title

Final Comments

This is the final Part to the current "A Rabbit Trail: Menu-Driven Bash Script", for now. We go back to our regularly-scheduled programming.  Web Apps / Web Services. We are going to explore converting our previous Web App into a REST client.

Stay Tuned!

Create data driven applications in Qlik’s free and easy to use coding environment, brought to you in partnership with Qlik.

Topics:
cygwin ,bash ,web dev

Opinions expressed by DZone contributors are their own.

The best of DZone straight to your inbox.

SEE AN EXAMPLE
Please provide a valid email address.

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.
Subscribe

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}