0

Writing bash script and don't know how to use more that one function in predicate:

#!/bin/bash
set -x

WAITED=0

registered () {
    VBoxManage showvminfo --machinereadable "$1" 2>/dev/null | grep UUID=
}

not_running () {
    VBoxManage showvminfo --machinereadable "$1" 2>/dev/null | grep 'VMState="poweroff"'
}

while registered "$1" && not_running "$1" && [ $WAITED -lt 60 ]
do
    echo "LOOP"
    VBoxManage controlvm "$1" acpipowerbutton 2>/dev/null
    ((WAITED++))
    sleep 1
done


if registered "$1" && ! not_running "$1"
then
    echo "POWEROFF"
    VBoxManage controlvm "$1" poweroff 2>/dev/null
    sleep 1
fi

if registered "$1"
then
echo "UNREG"
    VBoxManage unregistervm "$1" --delete 2>/dev/null
fi

Output:

./stop_vm 1b76
+ WAITED=0
+ registered 1b76
+ VBoxManage showvminfo --machinereadable 1b76
+ grep UUID=
UUID="cee02a9a-9a9a-4313-b297-479ca0a41e01"
+ not_running 1b76
+ VBoxManage showvminfo --machinereadable 1b76
+ grep 'VMState="poweroff"'
+ registered 1b76
+ grep UUID=
+ VBoxManage showvminfo --machinereadable 1b76
UUID="cee02a9a-9a9a-4313-b297-479ca0a41e01"
+ not_running 1b76
+ VBoxManage showvminfo --machinereadable 1b76
+ grep 'VMState="poweroff"'
+ echo POWEROFF
POWEROFF
+ VBoxManage controlvm 1b76 poweroff
+ sleep 1
+ WAITED=0
+ registered 1b76
+ VBoxManage showvminfo --machinereadable 1b76
+ grep UUID=
UUID="cee02a9a-9a9a-4313-b297-479ca0a41e01"
+ not_running 1b76
+ VBoxManage showvminfo --machinereadable 1b76
+ grep 'VMState="poweroff"'
VMState="poweroff"
+ '[' 0 -lt 60 ']'
+ echo LOOP
LOOP
+ VBoxManage controlvm 1b76 acpipowerbutton
+ (( WAITED++ ))
+ sleep 1
+ registered 1b76
+ VBoxManage showvminfo --machinereadable 1b76
+ grep UUID=
UUID="cee02a9a-9a9a-4313-b297-479ca0a41e01"
+ echo UNREG
UNREG
+ VBoxManage unregistervm 1b76 --delete
cara@bmserver1-sandbox:~/vm$ + registered 1b76
+ VBoxManage showvminfo --machinereadable 1b76
+ grep UUID=
+ registered 1b76
+ VBoxManage showvminfo --machinereadable 1b76
+ grep UUID=
+ registered 1b76
+ VBoxManage showvminfo --machinereadable 1b76
+ grep UUID=

Why POWEROFF comes before LOOP? There are no outer loops. What is the correct way to write predicates with several functions?

Jonas
  • 4,683
  • 4
  • 45
  • 81
  • You don't need the `return $?` statements. The exit status of a function is the exit status of the last command executed. – chepner Jan 23 '17 at 12:54
  • Given that nothing is running in the background, I don't see how "POWEROFF" could possibly print before "LOOP". I suggest running with `bash -x` to trace the execution of the script. – chepner Jan 23 '17 at 12:58
  • Double quote your arguments and variables when scripting! makes your life easier! – Inian Jan 23 '17 at 12:59
  • Done as you say, but problem stays. – Jonas Jan 23 '17 at 13:23
  • Are you 100% sure that you do not have a lonely "&" in your script (as opposed to the logical operator "&&", which is something entirely different)? – Fred Jan 23 '17 at 13:26
  • Also, there is no way in the code you posted that `WAITED=0` can be executed again. You aren't running the code you think you are. – chepner Jan 23 '17 at 13:40
  • 2
    Is it possible that this script be called recursively by VBox when VBoxManage controlvm "$1" acpipowerbutton 2>/dev/null is executed? It seems to be called "stop_vm", could that be some sort of "event" script? – Fred Jan 23 '17 at 13:44
  • It turns out that exactly that was happening. Thank's Fred ! – Jonas Jan 23 '17 at 13:46

1 Answers1

0

The problem may be caused by your script being recursively called by the VBox system when executing the body of the while loop in the "LOOP" section of your code. If it is the case, then you would need to rework your script to avoid recursion (with some kind of mutex mechanism), or perform the required actions in another script.

You should probably quote your expansion of positional arguments (like "$1"), and your use of return $? is redundant (a function, left to itself, always returns the return code of the last statement executed before exiting the function).

Fred
  • 6,590
  • 9
  • 20
  • This doesn't explain how the loop could execute after the `if` statement that prints POWEROFF. – chepner Jan 23 '17 at 13:08
  • As is, I would tend to agree. But suppose there is some code missing, and there is a "while" loop enclosing all of this (except the initial assignment), and that at first conditions are such that the "LOOP" while loop never executes, and "POWEROFF" is triggered. This is why I asked if we had the whole code. I am grasping at straws... – Fred Jan 23 '17 at 13:13
  • You should update this with the actual answer (nice catch!) or delete this. – chepner Jan 23 '17 at 14:31