LinuxQuestions.org
Review your favorite Linux distribution.
Home Forums Tutorials Articles Register
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices


Reply
  Search this Thread
Old 06-22-2012, 10:48 AM   #1
jao_madn
Member
 
Registered: Jun 2010
Posts: 47

Rep: Reputation: 0
problem run script inside a gnome-terminal


hi,

I would like to ask about using gnome-terminal command, I had a script that will run my VBOX VM in headless and i want to display the output(STDOUT) on the gnome-terminal window. The purpose that i want to display the STDOUT of the script cause i will used it or create a desktop shortcut for one click start all and want a visual display of the script running all the VM's for confirmation. The script works fine when i used in terminal. It failed to run the Script if i will used the "gnome-terminal -e" command. "Its like it runs all the command inside the script and STDOUT it on gnome-terminal window that pop-up and as soon as the script exit all the command inside the script will abort or simple the VM state will abort or stop running"already try all the option on gnome-terminal but unsuccesfull. Here are some i tried:
Quote:
gnome-termial -e "bash /home/<location_script>/startvm.bsh"
gnome-termial -e "/home/<location_script>/startvm.bsh
i also used --working-directory, profile i guess all argument in gnome-terminal.

My goal would be run all the command inside the script and if the script exit and also the gnome-terminal exit all the command inside the script won't be affected.

Hope someone knows something..

Thanks in advance..
 
Old 06-22-2012, 11:21 AM   #2
Nominal Animal
Senior Member
 
Registered: Dec 2010
Location: Finland
Distribution: Xubuntu, CentOS, LFS
Posts: 1,723
Blog Entries: 3

Rep: Reputation: 948Reputation: 948Reputation: 948Reputation: 948Reputation: 948Reputation: 948Reputation: 948Reputation: 948
Quote:
Originally Posted by jao_madn View Post
My goal would be run all the command inside the script and if the script exit and also the gnome-terminal exit all the command inside the script won't be affected.
When a terminal closes, it sends a TERM signal to all processes connected to that terminal.

If you want to run a command that will not die when the terminal closes, you need to detach the command from the terminal. The simplest and safest way to do that in Bash is to run the command via
Code:
( setsid command... </dev/null &>/dev/null & )
This will start the command... in a new process group (session), with standard input and output redirected to /dev/null. Because the entire stanza is in parentheses with an ampersand, it is actually run in the background of a subshell; that causes the command... to be reparented to init, and lose any dependence on the current terminal.

Note that if you need to supply input to the command, you can redirect its standard input from any file; it does not have to be /dev/null. Similarly, if you want to see the output, just redirect standard output and/or standard error to a file or files instead of /dev/null.

Questions?
 
Old 06-22-2012, 12:47 PM   #3
jao_madn
Member
 
Registered: Jun 2010
Posts: 47

Original Poster
Rep: Reputation: 0
Quote:
Originally Posted by Nominal Animal View Post
When a terminal closes, it sends a TERM signal to all processes connected to that terminal.

If you want to run a command that will not die when the terminal closes, you need to detach the command from the terminal. The simplest and safest way to do that in Bash is to run the command via
Code:
( setsid command... </dev/null &>/dev/null & )
This will start the command... in a new process group (session), with standard input and output redirected to /dev/null. Because the entire stanza is in parentheses with an ampersand, it is actually run in the background of a subshell; that causes the command... to be reparented to init, and lose any dependence on the current terminal.

Note that if you need to supply input to the command, you can redirect its standard input from any file; it does not have to be /dev/null. Similarly, if you want to see the output, just redirect standard output and/or standard error to a file or files instead of /dev/null.

Questions?
Thanks @Nominal Animal: Thanks for the FYI. Thats very new to me. I hope you can show/help me on my objective which would be run gnome-terminal command which pop-up a gnome-terminal window. run & display the STDOUT of the startvm.bsh on the pop-up gnome-terminal for the purpose of displaying if command "vboxheadless ..." succesfully executed(poweron) the VM then exit the script and then close the gnome-terminal window. Close all (gnome-terminal window, shell etc) after displaying the STDOUT of the script but not affecting the command the script execute(don't poweroff the VM).

I tried
Quote:
gnome-termial -e "bash /home/<location_script>/startvm.bsh"
gnome-termial -e "/home/<location_script>/startvm.bsh
But as soon as the gnome-terminal or maybe the script exit the VM will poweroff state.

Last edited by jao_madn; 06-22-2012 at 12:48 PM.
 
Old 06-22-2012, 08:52 PM   #4
Nominal Animal
Senior Member
 
Registered: Dec 2010
Location: Finland
Distribution: Xubuntu, CentOS, LFS
Posts: 1,723
Blog Entries: 3

Rep: Reputation: 948Reputation: 948Reputation: 948Reputation: 948Reputation: 948Reputation: 948Reputation: 948Reputation: 948
Quote:
Originally Posted by jao_madn View Post
my objective [..] would be run gnome-terminal command which pop-up a gnome-terminal window [..] for the purpose of displaying if command "vboxheadless ..." succesfully executed(poweron)
I would personally approach the issue from the opposite direction.

First, fix the startvm.bash scripts to return success when the VM starts successfully, and failure (e.g. exit 1) otherwise. If they need to start any long-running processes, they need to detach those. The script must exit when VM startup is complete; it cannot just stay running.

After that, it would be easy to write a script that uses zenity to display a list of VMs -- perhaps something like
Code:
zenity --list --checklist --separator=$'\n' --title="Select VMs" --column="Start" --column="Name" 1 VM-Foo 2 VM-Bar 3 VM-Baz
so the user can pick the VMs to start. During the startup, it can show a zenity progress bar, similar to
Code:
dd if=/dev/zero of=/dev/stdout bs=1 count=1000000 | zenity --progress --pulsate
and finally pop up a window to notify if any of the VMs were or were not started properly, depending on what you find most useful. (I prefer to be notified of errors only, but for mission critical stuff, I might like a success notification too.)

Could you (remove any sensitive information and) post the startvm.bash script?
 
Old 06-23-2012, 06:23 AM   #5
jao_madn
Member
 
Registered: Jun 2010
Posts: 47

Original Poster
Rep: Reputation: 0
@Nominal Animal: Yup, if i fail on this gnome-terminal then i guess zenity would be my next option,(im using but not most often zenity), i choose gnome-terminal for displaying the STDOUT of the script (start all vm in the script display success & failure on a popup terminal and gone) since i believe in zenity you need to have something first like a tmp file and then cat to display in a notification/display window but its my second option.

Yup i put conditional statement to check if VM start and exit the script with exit 0

Here are my startvm.bsh

Quote:
#!/bin/bash
#
runas_user () {
if [[ $EUID -eq 0 ]]; then # comment out
echo "This script is not allowed to run as root user" 2>&1 # this part for
exit 1 # normal user permission script
fi
}
runas_root () {
if [[ $EUID -ne 0 ]]; then # comment out
echo "This script is not allowed to run as normal user" 2>&1 # this part for
exit 1 # root user permession script
fi
}

vmstate () {
vboxmanage showvminfo "$1" |grep State|awk '{print $2}'
}

## VM state string value
## ON=running
## OFF=powered
linux01="89515c29-2bea-43f0-996d-29c009e27beb"
linux02="adc0f005-531c-4f94-889a-c4a706f529cc"
win2003="94fff2b2-0ba7-47db-82c4-5d922d78924a"
Others

run_user
if [ "$(vmstate "$win2003")" = running ] ; then
echo '------------------------------------------------'
echo '-- Win2003 Server Headless already started -----'
echo '------------------------------------------------'
else
echo '------------------------------------------------'
echo '-------Starting Win2003 Server Headless VM ------------'
echo '------------------------------------------------'
vboxheadless --startvm "$win2003" --vrde off > /dev/null 2>&1 &
fi

sleep 10

if [ "$(vmstate "$linux01")" = running ] ; then
echo '------------------------------------------------'
echo '------Linux01 Headless already started ---------'
echo '------------------------------------------------'
else
echo '------------------------------------------------'
echo '-------Starting linux01 Headless VM ------------'
echo '------------------------------------------------'
vboxheadless --startvm "$linux01" --vrde off > /dev/null 2>&1 &
fi

sleep 2

if [ "$(vmstate "$linux02")" = running ] ; then
echo '------------------------------------------------'
echo '------Linux02 Headless already started ---------'
echo '------------------------------------------------'
else
echo '------------------------------------------------'
echo '-------Starting linux02 Headless VM ------------'
echo '------------------------------------------------'
vboxheadless --startvm "$linux02" --vrde off > /dev/null 2>&1 &
fi

sleep 5

exit 0
I also tried to run vboxheadless with exec or source.

Thanks for the continues responce..sorry late for this response i just arrive at work.
 
Old 06-23-2012, 03:26 PM   #6
Nominal Animal
Senior Member
 
Registered: Dec 2010
Location: Finland
Distribution: Xubuntu, CentOS, LFS
Posts: 1,723
Blog Entries: 3

Rep: Reputation: 948Reputation: 948Reputation: 948Reputation: 948Reputation: 948Reputation: 948Reputation: 948Reputation: 948
Let's see. I would use vboxmanage list vms to list all known VMs, and vboxmanage list runningvms to check which ones are running.

To start a VM, you need to use the command I showed earlier, to detach it from the terminal, otherwise it will be killed when the terminal closes. In other words,
Code:
( setsid vboxheadless --startvm "$VM" --vrde off </dev/null &>/dev/null & )
To stop that VM, you only need to run
Code:
vboxmanage controlvm "$VM" poweroff
Here is the basic skeleton script I'd start with:
Code:
#!/bin/bash

# Only split tokens at newlines.
IFS=$'\n'

# Helper constants to be used in glob patterns
WSQ=$'[\t\n\v\f\r \042\047]'            # Whitespace or quotes
WSQB=$'[\t\n\v\f\r \042\047\173\175]'   # Whitespace, quotes or braces

# Update VM list.
VMRefresh () {
    VMCount=0       # Number of VMs
    VMID=()         # List of VM ID's
    VMDesc=()       # List of VM descriptions
    VMRunning=()    # "TRUE" if the VM is currently running

    local line="" desc="" code="" temp="" count=0

    while read line ; do
        # Split the line at the opening brace, {.
        desc="${line%%\{*}"
        code="${line##*\{}"

        # Remove leading and trailing whitespace and quotes from desc.
        temp=""
        while [ "$desc" != "$temp" ]; do
            temp="$desc"
            desc="${desc#$WSQ}"
            desc="${desc%$WSQ}"
        done

        # Remove leading and trailing whitespace, quotes and braces from desc.
        temp=""
        while [ "$code" != "$temp" ]; do
            temp="$code"
            code="${code#$WSQB}"
            code="${code%$WSQB}"
        done

        # Add to VMList.
        VMID[VMCount]="$code"
        VMDesc[VMCount]="$desc"
        VMRunning[VMCount]="FALSE"
        VMCount=$((VMCount+1))
    done < <( vboxmanage list vms )

    # Check which ones are currently running.
    while read line ; do
        # Split the line at the opening brace, {.
        code="${line##*\{}"

        # Remove leading and trailing whitespace, quotes and braces from desc.
        temp=""
        while [ "$code" != "$temp" ]; do
            temp="$code"
            code="${code#$WSQB}"
            code="${code%$WSQB}"
        done

        # Find the matching ID, and mark it running.
        for (( i = 0; i < VMCount; i++ )); do
            if [ "${VMID[i]}" = "$code" ]; then
                VMRunning[i]="TRUE"
                break
            fi
        done
    done < <( vboxmanage list runningvms )

    return 0
}

# Initialize VM list.
VMCount=0
VMID=()
VMDesc=()
VMRunning=()
VMRefresh

# Construct a list for zenity.
ZList=()
for (( vm = 0; vm < VMCount; vm++ )); do
    ZList[${#ZList[@]}]="${VMRunning[vm]}"
    if [ "${VMRunning[vm]}" = "TRUE" ]; then
        ZList[${#ZList[@]}]="Yes"
    else
        ZList[${#ZList[@]}]="No"
    fi
    ZList[${#ZList[@]}]="${VMDesc[vm]}"
    ZList[${#ZList[@]}]="${VMID[vm]}"
done

# Ask the user which VMs to start/keep running.
if ! VMRun=($( zenity \
       --list --checklist \
       --title="VM Management" \
       --width="800" --height="600" \
       --text="Which VMs should run?" \
       --separator=$'\n' \
       --column="Run" --column="Running" --column="Virtual machine" --column="ID" \
       --hide-column="4" --print-column="4" \
       "${ZList[@]}"
    ) ) ; then
    printf 'Cancelled.\n' >&2
    exit 0
fi

# Construct a list of VM IDs that are to be started, not yet running.
VMStart=()
for id in "${VMRun[@]}" ; do
    for (( i = 0; i < VMCount; i++ )); do
        if [ "${VMID[i]}" = "$id" ]; then
            if [ "${VMRunning[i]}" = "FALSE" ]; then
                VMStart[${#VMStart[@]}]="$id"
            fi
            break
        fi
    done
done

# Construct a list of VM IDs that are running, but should be stopped.
VMStop=()
for (( i = 0; i < VMCount; i++ )); do
    if [ "${VMRunning[i]}" = "TRUE" ]; then
        run=0
        for id in "${VMRun[@]}" ; do
            if [ "$id" = "${VMID[i]}" ]; then
                run=1
                break
            fi
        done
        if [ $run -eq 0 ]; then
            VMStop[${#VMStop[@]}]="$id"
        fi
    fi
done

#
# TODO: Modify the rest of the script!
#

# Start the new VMs.
for id in "${VMStart[@]}" ; do
    ( setsid vboxheadless --startvm "$id" --vrde off </dev/null &>/dev/null & )
done

# Stop the desired VMs.
for id in "${VMStop[@]}" ; do
    vboxmanage controlvm "$id" poweroff
done
As it is now, it will start and stop the VMs, but it will not monitor their status. It is easy enough to add to the script, but since there are many ways to do it properly, I didn't want to impose one at random. (I wrote the VMRefresh as a shell function, so the monitoring part can simply call it every second or so, to detect the changes in the VMs. You'll also need a loop or two to check if the desired VMs have been started/stopped.)

It is not at all difficult to use another zenity window to monitor the status of the started machines, and the shutdown progress for the stopped VMs. Or you can use one window for started VMs, and one for stopped VMs. They can be made to close automatically after a specific timeout. Or you can use a terminal. Or you can use notify-send to pop up notification messages about any changes the script sees.

It would be very simple to use a zenity window to report the status of all the VMs, with "Not running" for those that the user did not select to be started, "Running" for those that the user kept running, "Starting" and "Started" for those the user wanted started, and "Stopping"/"Stopped" for those the user wants stopped. The user can dismiss the window at any time; the virtual machines have already been asked to do what the user wanted, and the script and the window just monitor what is actually happening.

Could you run the above script, and tell me if the VM selection is what you had in mind? Or if you want it text-based, without zenity? Or in some other form? Note that clicking "Cancel" in the zenity window means the script will not start or stop any VMs.

After the selection is the way you want it, you can describe if/how you want the VM startup/poweroff to be monitored, and we can modify the script to do it that way.

Because the VM bootup process can take a minute or two, I'd use a bit trickier approach: I'd use a small shared folder across all VMs, and have each VM create an empty file there at the end of the boot process, named after the VM (using eg. a very simple /etc/init.d/bootup-ok script in Linux, something else for other OSes). Then, this script could first remove the file before starting the VM, and wait for the file to appear (during waiting the status would be "booting.." or something); after the file is seen, we know the VM has booted up properly. If it does not appear in say ten or fifteen minutes, there is something wrong, and the user can be alerted to check it.
 
  


Reply



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
[SOLVED] udev to run script not behaves like when run in terminal matiasar Linux - Software 6 04-17-2012 07:56 AM
how to run a script inside a flash after mounting it mindgames Linux - Newbie 3 09-13-2011 10:23 AM
What if a script inside another script fails to run? saiteju Programming 3 02-02-2010 11:35 PM
Run command as root inside script an_sush Linux - Newbie 19 09-04-2009 08:19 AM
Bash Script Help - Trying to create a variable inside script when run. webaccounts Linux - Newbie 1 06-09-2008 02:40 PM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 02:07 AM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration