LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Programming (https://www.linuxquestions.org/questions/programming-9/)
-   -   Bash Beginner (https://www.linuxquestions.org/questions/programming-9/bash-beginner-4175604607/)

SoberPistachio 04-25-2017 06:08 PM

Bash Beginner
 
Bash 4.3.46(1)-release (x86_64-pc-linux-gnu) @ Ubuntu MATE

I wrote a little Bash script called work. It uses a case statement for its main menu, listing several options. Option one is the function fam, fping asset monitor, a simple while loop that pings a list of IP addresses.

While I have the main menu of the work script open in terminator, I want to launch this while loop in a separate terminator window of a certain size. Is this possible?

Meanwhile, I copied the while loop (fam) to its own file in /usr/local/bin, and currently start fam with
Code:

terminator -b --geometry=186x450 -x fam &>/dev/null &
Code:

fam() {
        while true; do
            tput clear
            for ip in "${List1[@]}" "${List2[@]}"; do
            # Lines in ovpnip.txt read AssetTag,IPAddress (1505,10.7.1.21)
            # Remove all including & after comma, leaving Asset Tag, e.g., 1505
            assettag=$(grep "$ip" <"$workdir"/ovpnip.txt | sed -e 's/,.*//')
            if ! fping -c 2 "$ip" &>/dev/null; then
                echo -e "\e[31m- DN "$assettag" \e[96m@ \e[31m"$ip" -\e[96m"
                else
                    echo -e "\e[32m+ UP "$assettag" \e[96m@ \e[32m"$ip" +\e[96m"
            fi
            done
            echo -e "\nLooping heartbeat in...\n"
            for i in {9..1..1}; do
            echo -ne "        ...$i...\n" && sleep 1
            done
        done
}

Thanks!

ondoho 04-26-2017 01:29 AM

i think your current solution is acceptable.
you could also try starting the new window from within the fam function:
Code:

fam() {
        terminator -x sh -c 'while true; do
            tput clear
            for ip in "${List1[@]}" "${List2[@]}"; do
            # Remove all including & after comma, leaving Asset Tag, e.g., 1085
            assettag=$(grep "$ip" <"$workdir"/ovpnip.txt | sed -e 's/,.*//')
            if ! fping -c 2 "$ip" &>/dev/null; then
                echo -e "\e[31m- DN "$assettag" \e[96m@ \e[31m"$ip" -\e[96m"
                else
                    echo -e "\e[32m+ UP "$assettag" \e[96m@ \e[32m"$ip" +\e[96m"
            fi
            done
            echo -e "\nLooping heartbeat in...\n"
            for i in {9..1..1}; do
            echo -ne "        ...$i...\n" && sleep 1
            done
        done'
}

not tested.
you will have to fix the single quotes inside the single-quoted script.

Ramurd 04-26-2017 06:30 AM

since ondoho's solution might cause some issues with quotes, I thought... maybe it can be done differently.
With a here-document; Due to not having a terminator here, I used konsole instead, but the idea remains; it kind of works too:

Code:

scrippie=$(cat <<_EOF
while true
do
printf "."
sleep 1
done
_EOF
)

konsole -e /bin/bash "${scrippie}"


SoberPistachio 04-27-2017 04:34 PM

1 Attachment(s)
Thank you both.

Attempting
Code:

terminator -x sh -c 'while true; do'...
and correcting for the internal single quotes yields
/usr/local/bin/work: line 81: syntax error near unexpected token `do'
/usr/local/bin/work: line 81: ` terminator -x sh -c while true; do'
I could have easily messed up the quoting. Will google more and keep trying.


Here is what I have at the moment for the heredoc, which does indeed work. Somewhat. :)
Code:

#!/usr/bin/env bash

list1=("10.7.1.45" "10.7.1.46" "10.7.1.47" "10.7.1.48")
list2=("10.7.1.31" "10.7.1.32" "10.7.1.33" "10.7.1.34" \
"10.7.1.35" "10.7.1.36" "10.7.1.37" "10.7.1.38")
workdir=$HOME/.work

scrippie=$(cat <<_EOF
while true; do
    tput clear
    for ip in "${list1[@]}" "${list2[@]}"; do
        # Remove everything including and after the comma, leaving the Asset Tag, e.g., 1085
        assettag=$(grep "$ip" <"$workdir"/ovpnip.txt | sed -e 's/,.*//')
        if ! fping -c 2 "$ip" &>/dev/null; then
            echo -e "\e[31m- DN "$assettag" \e[96m@ \e[31m"$ip" -\e[96m"
            else
                echo -e "\e[32m+ UP "$assettag" \e[96m@ \e[32m"$ip" +\e[96m"
        fi
    done
    echo -e "\nLooping heartbeat in...\n"
    for i in {9..1..1}; do
        echo -ne "        ...$i...\n" && sleep 1
    done
done
_EOF
)

terminator -b --geometry=186x450 -x sh -c "${scrippie}"

The heredoc results in the following error, but opens a terminator window at the right size! None of the variables are expanding though, they are simply missing from the output. See the attached image. The sed part may be working I think (assettag=$(grep "$ip" <"$workdir"/ovpnip.txt | sed -e 's/,.*//'))...because the 3rd column on each line (1617, boipad (Bo's iPad)) and so on are proper Asset Tags.
Code:

** (terminator:14510): WARNING **: Binding '<Shift><Control><Alt>a' failed!
Unable to bind hide_window key, another instance/window has it.
PluginRegistry::load_plugins: Importing plugin __init__.py failed: 'module' object has no attribute 'AVAILABLE'

Using terminator -b --geometry=186x450 -e sh -c "${scrippie}" opens a window with a $ and a blinking cursor.

* Edit 2: Will keep reading and playing around until something sticks. Thanks again!

ondoho 04-28-2017 01:10 AM

Quote:

Originally Posted by SoberPistachio (Post 5703183)
Attempting
Code:

terminator -x sh -c 'while true; do'...
and correcting for the internal single quotes yields
/usr/local/bin/work: line 81: syntax error near unexpected token `do'
/usr/local/bin/work: line 81: ` terminator -x sh -c while true; do'
I could have easily messed up the quoting. Will google more and keep trying.

well show us the whole script, i'm sure it's fixable.
sed can usually use double quotes as well.

Ramurd 04-28-2017 08:22 AM

The syntax error (unexpected token do) I had at first, that's why I preceded the "${scrippie}" with /bin/bash.

BW-userx 04-28-2017 08:47 PM

Code:


#!/bin/bash

# This script opens 4 terminal windows.

i="0"

while [ $i -lt 4 ]
do
xterm &
i=$[$i+1]
done

your while [ true ] ; do

try that ...

I do not know if you should pipe | that or not
wouldn't hurt to try. I'm signing off or I've a tried it before posting.. so I'll just leave you with that idea to try instead.

Code:

terminator -x sh -c | while [ true ] ;
do
..
..
...
done


SoberPistachio 04-29-2017 02:10 AM

Heredoc method
Code:

#!/usr/bin/env bash

list1=("10.7.1.45" "10.7.1.46" "10.7.1.47" "10.7.1.48")
list2=("10.7.1.31" "10.7.1.32" "10.7.1.33" "10.7.1.34" \
"10.7.1.35" "10.7.1.36" "10.7.1.37" "10.7.1.38")
workdir=$HOME/.work

mainMenu() {
while true; do
    echo -e "\n1. fping monitor"
    echo "2. quit"
    echo ""; read -p '>>> ' response
    case $response in
        1) terminator -b --geometry=186x450 -e sh -c "${fam}" ;;
        2) exit 0 ;;
        *) echo -e "\nInvalid option: "$response". Reloading...\n"; sleep 1; mainMenu ;;
    esac
done
}

fam=$(cat <<_EOF
while true; do
    tput clear
    for ip in "${list1[@]}" "${list2[@]}"; do
        assettag=$(grep "$ip" <"$workdir"/ovpnip.txt | sed -e 's/,.*//')
        if ! fping -c 2 "$ip" &>/dev/null; then
            echo -e "\e[31m- DN "$assettag" \e[96m@ \e[31m"$ip" -\e[96m"
            else
                echo -e "\e[32m+ UP "$assettag" \e[96m@ \e[32m"$ip" +\e[96m"
        fi
    done
    echo -e "\nLooping heartbeat in...\n"
    for i in {9..1..1}; do
        echo -ne "        ...$i...\n" && sleep 1
    done
done
_EOF
)

mainMenu

Running this in terminator...

- Opens a new terminator window with a $ prompt and a blinking cursor
- The following error displays in the parent window:

Code:

** (terminator:29590): WARNING **: Binding '<Shift><Control><Alt>a' failed!
Unable to bind hide_window key, another instance/window has it.
PluginRegistry::load_plugins: Importing plugin __init__.py failed: 'module' object has no attribute 'AVAILABLE'

Changing mainMenu option 1 from -e sh -c to -x sh -c comes closest to the goal:

- The same bind hide_window key error displays in the parent terminal but
- A new terminator window opens
- The attached image in post #4 above shows what the new terminator window displays when using -x sh -c. Items in the 3rd column are asset tags.

Two other things with the here document that didn't work:

1. Modifying mainMenu option 1 to read -x /bin/bash "${fam}" instead of -x sh -c...
  • Same bind hide_window key error in the parent terminal
  • The new window opens and closes too fast to read

2. -e /bin/bash "${fam}" made terminator barf a wall of text all over the parent window. But expansion and sed appear to have worked.
Code:

Usage: terminator [options]

terminator: error: Additional unexpected arguments found: ['while true; do\n    tput clear\n    for ip in "10.7.1.45 10.7.1.46 10.7.1.47 10.7.1.48" "10.7.1.31 10.7.1.32 10.7.1.33 10.7.1.34 10.7.1.35 10.7.1.36 10.7.1.37 10.7.1.38"; do\n        assettag=1615\n1617\nboipad\npi01\n1618\n1619\n1620\n1621\n1622\n1623\n1624\n1625\n        if ! fping -c 2 "" &>/dev/null; then\n            echo -e "\\e[31m- DN "" \\e[96m@ \\e[31m"" -\\e[96m"\n            else\n                echo -e "\\e[32m+ UP "" \\e[96m@ \\e[32m"" +\\e[96m"\n        fi\n    done\n    echo -e "\\nLooping heartbeat in...\\n"\n    for i in {9..1..1}; do\n        echo -ne "        ......\\n" && sleep 1\n    done\ndone']


Non-heredoc method

Single quotes for sed were changed to double quotes.
Code:

#!/usr/bin/env bash

list1=("10.7.1.45" "10.7.1.46" "10.7.1.47" "10.7.1.48")
list2=("10.7.1.31" "10.7.1.32" "10.7.1.33" "10.7.1.34" \
"10.7.1.35" "10.7.1.36" "10.7.1.37" "10.7.1.38")
workdir=$HOME/.work

mainMenu() {
while true; do
    echo -e "\n1. fping monitor"
    echo "2. quit"
    echo ""; read -p '>>> ' response
    case $response in
        1) fam ;;
        2) exit 0 ;;
        *) echo -e "\nInvalid option: "$response". Reloading...\n"; sleep 1; mainMenu ;;
    esac
done
}

fam=() {
terminator -b --geometry=186x450 -x sh -c 'while true; do
    tput clear
    for ip in "${list1[@]}" "${list2[@]}"; do
        assettag=$(grep "$ip" <"$workdir"/ovpnip.txt | sed -e "s/,.*//")
        if ! fping -c 2 "$ip" &>/dev/null; then
            echo -e "\e[31m- DN "$assettag" \e[96m@ \e[31m"$ip" -\e[96m"
            else
                echo -e "\e[32m+ UP "$assettag" \e[96m@ \e[32m"$ip" +\e[96m"
        fi
    done
    echo -e "\nLooping heartbeat in...\n"
    for i in {9..1..1}; do
        echo -ne "        ...$i...\n" && sleep 1
    done
done'
}

mainMenu

- Prints the same bind hide_window key error
- New terminator window opens and closes too fast to see if it displays anything

The same results happen if -x sh -c is replaced with -e sh -c or -x /bin/bash.

Using -e /bin/bash summons wall barf. Unlike in the heredoc version of the script, it appears that neither expansion nor sed worked.
Code:

terminator: error: Additional unexpected arguments found: ['while true; do\n\t\ttput clear\n\t\tfor ip in "${list1[@]}" "${list2[@]}"; do\n\t\t\tassettag=$(grep "$ip" <"$workdir"/ovpnip.txt | sed -e "s/,.*//")\n\t\t\tif ! fping -c 2 "$ip" &>/dev/null; then\n                echo -e "\\e[31m- DN "$assettag" \\e[96m@ \\e[31m"$ip" -\\e[96m"\n                else\n                    echo -e "\\e[32m+ UP "$assettag" \\e[96m@ \\e[32m"$ip" +\\e[96m"\n\t\t\tfi\n\t\tdone\n\t\techo -e "\\nLooping heartbeat in...\\n"\n\t\tfor i in {9..1..1}; do\n\t\t\techo -ne "        ...$i...\\n" && sleep 1\n\t\tdone\n\tdone']
Not quite there yet... :)

ondoho 04-29-2017 04:09 AM

1) don't worry about the terminaltor keybind warning.

2) if you use the method i suggested, i think it doesn't know anything about the variables you use, i.e. list1, list2 and workdir, and therefore probably errors out.
you can pass them as command line options.

in post #1 you wrote that you had a working solution which had the script as a separate file.
i answered that that solution is acceptable imo.
you since edited post #1. please don't do that.

so, again: you had a working solution. i understand you weren't happy with it because it's somewhat inelegant?

SoberPistachio 04-29-2017 04:23 AM

1) Yes, warning not error, my mistake.
2) Yes, and many thanks!
I edited post #1 to include the comment that lines in ovpnip.txt read AssetTag,IPAddress, for a bit of clarification. :)

I guess I'm satisfied with the current solution, it does work after all. Just curious if there was a way to launch that function in a new terminator window from an existing session. Easy enough to do if the new window is a command + a few options, but I couldn't find examples of anything as lengthy as that while loop used in that way.

Edit: Piping terminator -b --geometry=186x450 -x /bin/bash | while true; do at the start of the function spawns a new window with the expected PS1 prompt, but the fam function runs inside the parent terminal.

Fat_Elvis 05-06-2017 02:31 PM

This works with XTerm.

Code:

if [[ -n "$DISPLAY" ]] && [[ -n "$WINDOWID" ]] ; then
        PROGNAM="$(basename $0)"
        ID="$(xprop -id "$WINDOWID" WM_NAME)"
        ID="${ID##* }"
        ID="${ID//\"/}"

        if [[ "$ID" != "$PROGNAM" ]] ; then
                xterm -geom "${GEOM}" -T "$PROGNAM" -e "$0" $@ &
                exit 0
        fi
fi


# Rest of your function goes here.

This works best when called as a separate script file, however. Otherwise you will have to dance around multiple fork and exit points which can get unpleasant.


All times are GMT -5. The time now is 08:32 PM.