While read won't run keyboard function

I am using while read do/ done to retrieve menu item.

Works as advertised, no problem.

I am using this hack function "pause" to stop script execution and wait for keyboard "enter" key to continue. Sort of break point function. Also works fine with one exception - it does not work when used within while do/done code.

No big issue, but like to know what so special with while do /cone code.

As far as I can tell I get no error or tracking info telling me why "pause" no longer waits for (any) key press. It just "passes thru " .

In this stripped down code I experience same problem when using "pause" in "inputBox" function

                         while read choice
  do
  echo $choice
  inputBox
  pause                # will  not wait for keyboard  
   done < results  

Here is partial output , no need to press "enter"

@line 463 Execute pause function 
+ pause
+ read -p 'Press [Enter] key to continue...'   

  code executed in "pause"  function 



 + echo '@line 466 Execute pause function '
@line 466 Execute pause function 

First off: while-loops are not special at all. AND you might want to investigate the select -keyword of the shell instead of rolling your own replacement for it.

One possible reason (to be honest there is too little information to accurately debug your problem) is that read reads from standard input. If you have redirected this input somewhere above in your script than it might read from some unexpected place.

I hope this helps.

bakunin

Thanks, I think you answered my question.
The whiptail menu while read "searches" are indeed redirected and pause expect stdio.

It will take me a while to fix that after I'll take a harder look at "redirection".

------ Post updated at 08:56 PM ------

OK, I thought I can fix this myself, but I guess not.


"${24}" "${25}" off \
 464  2>results        "redirected" stderr to file results 



function "pause"  uses stdio and test works fine here 



 465 echo "TOK HERE # $LINENO TEST PAUSE @line $LINEN0 TOK cut_TEST"
 466 pause 
 467 echo "TOK HERE # $LINENO TEST PAUSE @line $LINEN0 TOK cut_TEST"
 468 pause 
 469 echo "START read all positionining parameters" 
 470 #pause
 471 counter=1
 472 while read choice
 473  do


  reading from file "results "   (?) 



 474  echo "$LINENO TEST PAUSE @line $LINEN0 TOK cut_TEST"
 475  pause 



"pause" skips here 







 476  echo "$LINENO TEST PAUSE @line $LINEN0 TOK cut_TEST"
 477  pause 
 478  echo "STOP HERE %%%%%%%%%%%%%%%%%%%%%%%% @line $LINENO Execute pause func$
 479  pause 
 480  echo "@line $LINENO Execute pause function "


Now for the stupid question - all info about redirection talks about redirecting FILES.

What is the correct syntax to redirect FUNCTION ?
I assume I will have to change the redirection after the pause returns the flow back to the "while do/done "

Here is the copy of pause , it just waits for "enter" key when working correctly

pause(){
  echo "STOP HERE " 
  read -p "Press [Enter] key to continue..."  
}  

The read in the pause function competes with the read after while.
You can redirect the read to a keyboard device.

read -p "Press [Enter] key to continue..."  </dev/tty

Or you can redirect the whole function

pause </dev/tty

A good alternative is to use another descriptor for the while read

while read ... <&3
do
   ...
done 3< filename

The descriptor 3 does not clash with the standard descriptors 0=stdin, 1=stdout, 2=stderr

Short answer: because in UNIX everything is a file.

Long version: picture a process to be a garden hose. You pour water (data) into it at the top, inside something happens (the data is processed in some way), then the result comes out at the bottom.

Whatever comes out will land in a file called /dev/ttyX (or something similar, depending on your OS) which resembles the video hardware you are sitting at. Type something on your keyboard and some driver will move the typed characters into this file (from where some program - usually the shell - will pick them up), have the shell generate some output and it will land there, from where a driver picks it up and displays it on your screen. These two drivers basically constitute what is called a "terminal emulator".

To come back to the water hose picture: with redirection you can decide which device to attach to the various endings of the hose. Consider the command:

# ls

We usually say "it displays a directory listing", but in an absolute sense this is not the case: what it does is to generate a data stream with the directory information. We have a "hose" where nothing goes in and a stream of characters (the directory listing) comes out. Per default all the processes started from the shell are redirected to /dev/tty and this is why the generated data is displayed on your screen. But if we want it somewhere else we could re-redirect it somewhere else:

# ls > /some/file

Now we have attached a "different bucket" to the ending of the water hose and the data lands now in it. The same way we could redirect the input to a process. Because ls does not want or need any input we use grep for that:

grep "word" >/some/output </some/input

We have attached the file "/some/input" to the opening of the hose so the data in this file run into it. Inside "grep" does its work (it filters out lines containing "word", all others are dropped) and the result goes into another file attached to the bottom of the hose: "/some/output".

Now this is all fine but how about connecting a hose not to a bucket but another hose? We can do that too: this is called a "pipeline" and the symbol is "|". Let us have a look:

# ls | grep "myfile"

We have the first process ls which has no input but some output. This output is directly connected to the input of another process, grep , which further processes what ls emits. This now lands on the screen because of the default redirection i told you above, but we could further redirect this to another file or - by another pipeline - to another process.

It is even possible to create a filesystem representation of this pipeline: It looks like a file but in fact it is just a name where the output of one command is buffered until another command picks it up and processes it. This is called a "named pipe" and the command to create one is mkfifo .

Finally i want to confuse you hopelessly: the water hoses (processes) in UNIX are weird because they have, per default, not two openings, but three: stdin, stdout and stderr. Consider the hoses being Y-shaped, with two outlets, not one.

UNIX-processes use stdin for input. This is per default the keyboard as you can see when typing the command:

cat > /some/file

You will notice that this seems to "hang". In fact it does not hang but waits for input - your keystrokes. Type something and you will see that. Finally press CTRL-D, which creates the "END-OF-FILE"-character and all you have typed you will find in the file named "/some/file", which was what we redirected stdout to. Would we have not redirected it it would have landed on the screen - again, the default redirection.

This leaves stderr for explanation: this is where commands write their diagnostic messages to. It can be redirected the same way you can redirect stdout. Some are confused because these two are per default redirected both to the screen, so that both types of output land there. But if two different hoses deliver into the same bucket it doesn't mean they are identical! So let us try to separate them visibly:

# ls -l /etc/hosts /bla/foo/bar

Because "/etc/hosts" is a file that exists on practically every UNIX system and chances are "/bla/foo/bar" will not exist in yours you will get an output like this:

# ls -l /etc/hosts /bla/foo/bar
ls: cannot access '/bla/foo/bar': No such file or directory
-rw-r--r-- 1 root root 220 Jul 23 17:34 /etc/hosts

Notice that the first line has come via stderr, the second via stdout. No we will redirect away (to /dev/null , a file which devours everything sent to it - the trash can) the various parts:

# ls -l /etc/hosts /bla/foo/bar >/dev/null
ls: cannot access '/bla/foo/bar': No such file or directory

We have redirected stdin so that will not land on screen any more.

# ls -l /etc/hosts /bla/foo/bar 2>/dev/null
-rw-r--r-- 1 root root 220 Jul 23 17:34 /etc/hosts

Here we have redirected stderr. Notice that stdin, stdout and stderr are so-called "I/O-descriptors" and also numbered: 0 is stdin, 1 is stdout and 2 is stderr. This is why "2>" redirects stderr, the I/O-descriptor 2. We have left out 1 for our redirections up to now because it is the default but to be ultra-super-duper-correct we would write:

# ls -l /etc/hosts /bla/foo/bar 1>/dev/null
ls: cannot access '/bla/foo/bar': No such file or directory

to redirect stdin.

I am already at the end, just one more thing: it would be nice to have the possibilty to redirect an I/O-descriptor to where another is already redirected. There is such a device:

# ls -l /etc/hosts /bla/foo/bar >/some/file 2>&1

The first rediction sends all stdin to "/some/file". The second redirects stderr to whereever stdin is already pointing at - in this case into the same file. Notice, though, that order matters! All these redirections are interpreted from left to right! So this:

# ls -l /etc/hosts /bla/foo/bar 2>&1 >/some/file

Will not do the same as the command above, because first stderr will be redirected to where stdin points at - the screen - and only then stdin will be redirected to "/some/file", but this will not affect stderr at all.

I hope this helps.

bakunin