LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Linux - Newbie (https://www.linuxquestions.org/questions/linux-newbie-8/)
-   -   Fill effect in a shell script (https://www.linuxquestions.org/questions/linux-newbie-8/fill-effect-in-a-shell-script-4175433183/)

shivaa 10-20-2012 03:37 AM

Fill effect in a shell script
 
Good morning everyone..
It's a wierd question, but I am curious about it.
Let's say I have a script
Code:

for i in $file
do
echo "Command is working..."
<command>
done

You can see, I have used 3 dots in echo. So in a shell script is it possible to fill such an effect that until the command works, the 3 dots keep blinking? So it make an effect that some processing is going on. Although we used to see such effects in GUIs, but not in terminals. But can we do this?
Any opinion is most welcome!!

ntubski 10-20-2012 03:51 AM

As long as <command> doesn't produce any output, you can do some basic "animation" with carriage return "\r". This is a special character that moves the cursor the beginning of the line, so you can then overwrite the previous contents:
Code:

blink=0
while true ; do
    if ((blink)) ; then
        echo -n $'\rworking...'
    else
        echo -n $'\rworking  '
    fi
    sleep 0.5
    ((blink = !blink))
done

A more common thing is a sort of "hourglass" type animation:

Code:

#!/bin/bash
frames=('|' '/' '-' '\')
frame=0

while true ; do
    echo -n $'\r'"working... ${frames[frame]}"
    sleep 0.2
    ((frame = (frame + 1) % ${#frames[@]}))
done


shivaa 10-20-2012 10:58 AM

Thanks, but how can I impliment this code in my script? My test script is:
Code:

for i in $file
do
echo "Command is working...."
cmd=$(more $i | grep -w "20/Oct/2012" | wc -l)
echo $cmd
done

Suppose erroelogs i.e. $i is very large log file and command is taking 4 or 5 minutes to accomplish it, then in this period it want to insert that animation with my echo statement "Command is working....". I tried to add your code but failed... :(
Could you show me the way by modifying my script? Thanks a lot again!

ntubski 10-20-2012 11:17 AM

You can put the blinking loop in the background:
Code:

#!/bin/bash

blinker() {
    blink=0
    while true ; do
        if ((blink)) ; then
            echo -n $'\rworking...'
        else
            echo -n $'\rworking  '
        fi
        sleep 0.5
        ((blink = !blink))
    done
}

for i in $file
do
    blinker &
    blinker_pid=$!
    # piping from more was redundant, and grep's -c counts matching
    # lines so wc is not needed. The -F tells grep the pattern is just
    # a plain string, which may be more efficient to search for than a
    # regex.
    cmd=$(grep -F -c -w "20/Oct/2012" "$i")
    kill $blinker_pid
    echo $cmd
done


schneidz 10-20-2012 04:28 PM

i heard them referred to as spinners. this is my favorite spinner design:
Code:

frames=('\__' '_|_' '__/' '_|_')

shivaa 10-20-2012 11:52 PM

Quote:

Originally Posted by schneidz (Post 4811006)
i heard them referred to as spinners. this is my favorite spinner design:
Code:

frames=('\__' '_|_' '__/' '_|_')

Hmmm.. it's not so impressive! but what @ntubski has suggested is a really good interpretation of running process i.e frames=('|' '/' '-' '\').
Is there any way that same thing can be done with same type of symbols? I mean somthing like this:
.(wait some mili seconds).(wait).(wait)... Then again first .(wait) and so on...

schneidz 10-21-2012 07:00 AM

Quote:

Originally Posted by meninvenus (Post 4811165)
Hmmm.. it's not so impressive! but what @ntubski has suggested is a really good interpretation of running process i.e frames=('|' '/' '-' '\').
Is there any way that same thing can be done with same type of symbols? I mean somthing like this:
.(wait some mili seconds).(wait).(wait)... Then again first .(wait) and so on...

yeah:
Code:

frames=('.  ' '..  ' '... ' '....')

shivaa 10-21-2012 09:48 AM

Quote:

Originally Posted by schneidz (Post 4811300)
yeah:
Code:

frames=('.  ' '..  ' '... ' '....')

Exactly :-). This is what I was looking for!!
In addition to your frames variable, I just added one more empty values as:
Code:

frames=('    ' '.  ' '..  ' '... ' '....')
And that is what I was looking for. You'd find it more beautiful... like a twinkle twinkle little stars :-)

Thanks a lot Mr. ntubski and many thanks to Mr. schneidz also.

shivaa 10-21-2012 11:00 AM

Termination of a function in shell script
 
Following is my final script:
Code:

#!/bin/bash
## Blinker function
blinker ()
{
frames=('.  ' '..  ' '... ' '....')
frame=0

while true ; do
    echo -n $'\r'"Calculating count ${frames[frame]}"
    sleep 0.2
    ((frame = (frame + 1) % ${#frames[@]}))
done
}

## Script
blinker &
blinker_pid=$!
cmd=`grep -F -c -w "20/10/2012" /tmp/largefile.txt`  ## largefile.txt is a large text file, so command is taking 2 or 3 minutes to finish it.
echo "Total counts is: $cmd"
kill $blinker_pid

It's working ok and result a correct value but,
Problem 1# In output of the script, it gives me an error,
Quote:

"scriptname...1234 terminated blinker"
Which I want to avoid. So how to stop the function normally, instead of killing it's PID at the end.
Problem 2# If I want to stop the script in between processing using CTRL+C, it's not working and function is keep going on. One way is to kill script's PID, which I don't want. So what's a safe way to stop the script if I want to?

Rupadhya 10-21-2012 01:26 PM

I haven't been able to recreate your #1 issue yet, but you might do this to suppress the message with the following modification.
Code:

kill $blinker_pid 2>/dev/null
I will look at Issue #2 now.
- Raj

shivaa 10-21-2012 01:33 PM

Quote:

Originally Posted by Rupadhya (Post 4811536)
I haven't been able to recreate your #1 issue yet, but you might do this to suppress the message with the following modification.
Code:

kill $blinker_pid 2>/dev/null
I will look at Issue #2 now.
- Raj

Thanks Mr. Raj, I have tried this redirection to /dev/null, but it didn't work.
Meanwhile, I put a exit 0 just as:
Code:

....
....
echo "Total counts is: $cmd"
kill $blinker_pid
exit 0

And it worked fine.
But now my question is, how to terminate a script in between processing, I mean beofore it gets finished?

Rupadhya 10-21-2012 01:48 PM

Try this.. What the trap command does is it traps the SIGINT signal and passes control to the control_c function.
Code:

#!/bin/bash
## Blinker function
blinker ()
{
frames=('.  ' '..  ' '... ' '....')
frame=0

while true ; do
    echo -n $'\r'"Calculating count ${frames[frame]}"
    sleep 0.2
    ((frame = (frame + 1) % ${#frames[@]}))
done
}
 
control_c()
# run if user hits control-c
{
  kill $blinker_pid 2>/dev/null
  echo -en "\n*** Why did you hit ctrl-c?  I was grepping a large file! ***\n"
  exit 1
}
 
# trap keyboard interrupt (control-c)
trap control_c SIGINT

## Script
blinker &
blinker_pid=$!
cmd=`grep -F -c -w "20/10/2012" /tmp/largefile.txt`  ## largefile.txt is a large
 text file, so command is taking 2 or 3 minutes to finish it.
echo "Total counts is: $cmd"
kill $blinker_pid 2>/dev/null

I don't know why the redirect to the /dev/null didn't work for you. The redirect to the /dev/null is meant to send the output to a black hole and never be seen again.

- Raj

rknichols 10-21-2012 02:13 PM

The "terminated" message doesn't come directly from the kill command but from the shell when it sees a child process that exited due to a signal. You need to insert this line at the top of the blinker() function:
Code:

trap "exit 0" TERM
Now the function will exit with a zero return code, and you will not get any message.

shivaa 10-21-2012 02:20 PM

Thank agian Raj. The trap cmd worked fine. I was also awere about this, but I was not sure how to use it this way. You showed me a good way!

shivaa 10-21-2012 02:24 PM

Quote:

Originally Posted by rknichols (Post 4811557)
The "terminated" message doesn't come directly from the kill command but from the shell when it sees a child process that exited due to a signal. You need to insert this line at the top of the blinker() function:
Code:

trap "exit 0" TERM
Now the function will exit with a zero return code, and you will not get any message.

I used it, but making no use. My script is working OK without this line. Could you elaborate it little more, please? What difference it can make in above mentioned script (by Raj)?


All times are GMT -5. The time now is 04:42 PM.