0

Run this in Ubuntu 14.04.1:

./script.sh MyVM take

Why does the echo line in the function list_snapshot work (it prints the value of those 3 variables) but the echo line in take_snapshot can't print the value of the variable $output and $old_snapshot_name but only print the value of $machine_name?

Note that the script works when I run ./script.sh MyVM take, it does delete the old snapshot and create a new snapshot.

#! /bin/sh

if [ ! "$1" ]; then
    echo "Usage: $0 <vmname> list|take"
    exit 1
else
    machine_name=$1
fi

list_snapshot () {
    output=$(VBoxManage snapshot "$machine_name" list)
    count=$(echo "$output" | grep -c 'UUID')

    echo "Machine '$machine_name' has '$count' snapshots: \n '$output'"
    return "$count"
}


take_snapshot () {
    echo "$output"
    while (list_snapshot; [ $? -gt 3 ])  
    do
        old_snapshot_name=$(echo "$output" | grep -o 'UUID: (.{36})' | head -1)
        echo "Deleting old snapshot '$old_snapshot_name' for machine '$machine_name'..."

        VBoxManage snapshot "$machine_name" delete "$old_snapshot_name"

    done

    current_time=$(date "+%Y.%m.%d-%H.%M.%S")
    snapshot_name=$machine_name.$current_time

    echo "Taking new snapshot '$snapshot_name' for machine '$machine_name'..."
    VBoxManage snapshot "$machine_name" take "$snapshot_name" --live 
}

case "$2" in
  list)
    list_snapshot
    ;;
  take)
    take_snapshot
    ;;
  *)
    echo "Usage: $0 <vmname> list|take"
    exit 1
    ;;
esac

Output without -x./snapshotVM.sh RancherOS-tools take

Machine 'RancherOS-tools' has '4' snapshots: 
 '   Name: RancherOS-tools.2015.11.03-11.25.12 (UUID: 7afef8ee-1915-4494-9634-add82e1a613f)
      Name: RancherOS-tools.2015.11.03-11.25.40 (UUID: 79a53543-377e-4a74-80ca-751883a7787b)
         Name: RancherOS-tools.2015.11.03-11.32.10 (UUID: 25a942fe-2d0a-4290-a98e-7d16ec4c60bd)
            Name: RancherOS-tools.2015.11.03-11.34.58 (UUID: 02af926b-396c-4ce6-bfb3-5e953de5a051) *'
Deleting old snapshot '' for machine 'RancherOS-tools'...
0%...10%...20%...30%...40%...50%...60%...70%...80%...90%...100%
Machine 'RancherOS-tools' has '3' snapshots: 
 '   Name: RancherOS-tools.2015.11.03-11.25.40 (UUID: 79a53543-377e-4a74-80ca-751883a7787b)
      Name: RancherOS-tools.2015.11.03-11.32.10 (UUID: 25a942fe-2d0a-4290-a98e-7d16ec4c60bd)
         Name: RancherOS-tools.2015.11.03-11.34.58 (UUID: 02af926b-396c-4ce6-bfb3-5e953de5a051) *'
Taking new snapshot 'RancherOS-tools.2015.11.03-11.35.20' for machine 'RancherOS-tools'...
0%...10%...20%...30%...40%...50%...60%...70%...80%...90%...100%
Snapshot taken. UUID: 5195881b-113b-448a-81e3-98a121c8fbfe

Output with -x./snapshotVM.sh RancherOS-tools take

dy@dy:~$ ./snapshotVM.sh RancherOS-tools take
+ [ ! RancherOS-tools ]
+ machine_name=RancherOS-tools
+ take_snapshot
+ echo 

+ list_snapshot
+ VBoxManage snapshot RancherOS-tools list
+ output=   Name: RancherOS-tools.2015.11.03-11.25.40 (UUID: 79a53543-377e-4a74-80ca-751883a7787b)
      Name: RancherOS-tools.2015.11.03-11.32.10 (UUID: 25a942fe-2d0a-4290-a98e-7d16ec4c60bd)
         Name: RancherOS-tools.2015.11.03-11.34.58 (UUID: 02af926b-396c-4ce6-bfb3-5e953de5a051)
            Name: RancherOS-tools.2015.11.03-11.35.20 (UUID: 5195881b-113b-448a-81e3-98a121c8fbfe) *
+ echo    Name: RancherOS-tools.2015.11.03-11.25.40 (UUID: 79a53543-377e-4a74-80ca-751883a7787b)
      Name: RancherOS-tools.2015.11.03-11.32.10 (UUID: 25a942fe-2d0a-4290-a98e-7d16ec4c60bd)
         Name: RancherOS-tools.2015.11.03-11.34.58 (UUID: 02af926b-396c-4ce6-bfb3-5e953de5a051)
            Name: RancherOS-tools.2015.11.03-11.35.20 (UUID: 5195881b-113b-448a-81e3-98a121c8fbfe) *
+ grep -c UUID
+ count=4
+ echo Machine 'RancherOS-tools' has '4' snapshots: \n '   Name: RancherOS-tools.2015.11.03-11.25.40 (UUID: 79a53543-377e-4a74-80ca-751883a7787b)
      Name: RancherOS-tools.2015.11.03-11.32.10 (UUID: 25a942fe-2d0a-4290-a98e-7d16ec4c60bd)
         Name: RancherOS-tools.2015.11.03-11.34.58 (UUID: 02af926b-396c-4ce6-bfb3-5e953de5a051)
            Name: RancherOS-tools.2015.11.03-11.35.20 (UUID: 5195881b-113b-448a-81e3-98a121c8fbfe) *'
Machine 'RancherOS-tools' has '4' snapshots: 
 '   Name: RancherOS-tools.2015.11.03-11.25.40 (UUID: 79a53543-377e-4a74-80ca-751883a7787b)
      Name: RancherOS-tools.2015.11.03-11.32.10 (UUID: 25a942fe-2d0a-4290-a98e-7d16ec4c60bd)
         Name: RancherOS-tools.2015.11.03-11.34.58 (UUID: 02af926b-396c-4ce6-bfb3-5e953de5a051)
            Name: RancherOS-tools.2015.11.03-11.35.20 (UUID: 5195881b-113b-448a-81e3-98a121c8fbfe) *'
+ return 4
+ [ 4 -gt 3 ]
+ echo 
+ head -1
+ grep -o UUID: (.{36})
+ old_snapshot_name=
+ echo Deleting old snapshot '' for machine 'RancherOS-tools'...
Deleting old snapshot '' for machine 'RancherOS-tools'...
+ VBoxManage snapshot RancherOS-tools delete 
0%...10%...20%...30%...40%...50%...60%...70%...80%...90%...100%
+ list_snapshot
+ VBoxManage snapshot RancherOS-tools list
+ output=   Name: RancherOS-tools.2015.11.03-11.32.10 (UUID: 25a942fe-2d0a-4290-a98e-7d16ec4c60bd)
      Name: RancherOS-tools.2015.11.03-11.34.58 (UUID: 02af926b-396c-4ce6-bfb3-5e953de5a051)
         Name: RancherOS-tools.2015.11.03-11.35.20 (UUID: 5195881b-113b-448a-81e3-98a121c8fbfe) *
+ echo    Name: RancherOS-tools.2015.11.03-11.32.10 (UUID: 25a942fe-2d0a-4290-a98e-7d16ec4c60bd)
      Name: RancherOS-tools.2015.11.03-11.34.58 (UUID: 02af926b-396c-4ce6-bfb3-5e953de5a051)
         Name: RancherOS-tools.2015.11.03-11.35.20 (UUID: 5195881b-113b-448a-81e3-98a121c8fbfe) *
+ grep -c UUID
+ count=3
+ echo Machine 'RancherOS-tools' has '3' snapshots: \n '   Name: RancherOS-tools.2015.11.03-11.32.10 (UUID: 25a942fe-2d0a-4290-a98e-7d16ec4c60bd)
      Name: RancherOS-tools.2015.11.03-11.34.58 (UUID: 02af926b-396c-4ce6-bfb3-5e953de5a051)
         Name: RancherOS-tools.2015.11.03-11.35.20 (UUID: 5195881b-113b-448a-81e3-98a121c8fbfe) *'
Machine 'RancherOS-tools' has '3' snapshots: 
 '   Name: RancherOS-tools.2015.11.03-11.32.10 (UUID: 25a942fe-2d0a-4290-a98e-7d16ec4c60bd)
      Name: RancherOS-tools.2015.11.03-11.34.58 (UUID: 02af926b-396c-4ce6-bfb3-5e953de5a051)
         Name: RancherOS-tools.2015.11.03-11.35.20 (UUID: 5195881b-113b-448a-81e3-98a121c8fbfe) *'
+ return 3
+ [ 3 -gt 3 ]
+ date +%Y.%m.%d-%H.%M.%S
+ current_time=2015.11.03-11.37.46
+ snapshot_name=RancherOS-tools.2015.11.03-11.37.46
+ echo Taking new snapshot 'RancherOS-tools.2015.11.03-11.37.46' for machine 'RancherOS-tools'...
Taking new snapshot 'RancherOS-tools.2015.11.03-11.37.46' for machine 'RancherOS-tools'...
+ VBoxManage snapshot RancherOS-tools take RancherOS-tools.2015.11.03-11.37.46 --live
0%...10%...20%...30%...40%...50%...60%...70%...80%...90%...100%
Snapshot taken. UUID: 0e11c8d0-130c-4508-a2be-8692fc9316bd

Update: looks like I meet some variable scope problem, after redesign my code, remove while loop, now it works

#! /bin/sh

# usage: 
# $0 <vmname> list : list all snapshot
# $0 <vmname> take : delete old snapshot name startwith "Backup" and leave 3 "Backup" snapshot

#set -x

if [ ! "$1" ]; then
    echo "Usage: $0 <vmname> list|take"
    exit 1
else
    machine_name=$1
fi

list_snapshot () {
    output=$(VBoxManage snapshot "$machine_name" list)
    count=$(echo "$output" | grep -c 'UUID')

    echo "Machine $machine_name has $count snapshots: "
    echo "$output"
}


take_snapshot () {
    output=$(VBoxManage snapshot "$machine_name" list)
    count=$(echo "$output" | grep -c 'Backup')

    echo "Machine $machine_name has $count snapshots: "
    echo "$output"

    if [ "$count" -ge 3 ]; then
        old_snapshots_uuid=$(echo "$output" | grep "Backup" | grep -Eo 'UUID: .{36}' | cut -c 7-42 | head -$((count-2)))

        for u in $old_snapshots_uuid; do
          echo "Deleting old snapshot $u for machine $machine_name..."
          VBoxManage snapshot "$machine_name" delete "$u"
        done    
    fi

    current_time=$(date "+%Y.%m.%d-%H.%M.%S")
    snapshot_name="Backup".$machine_name.$current_time

    echo "Taking new snapshot $snapshot_name for machine $machine_name..."
    VBoxManage snapshot "$machine_name" take "$snapshot_name"     
}

case "$2" in
  list)
    list_snapshot
    ;;
  take)
    take_snapshot
    ;;
  *)
    echo "Usage: $0 <vmname> list|take"
    exit 1
    ;;
esac
3
  • Also, does echo "$output" in take_snapshot () work? – kos Nov 3 '15 at 3:57
  • @kos No, not work, I have to copy output=$(VBoxManage snapshot "$machine_name" list) in list_snapshot into take_snapshot then it work , don't know why can't just using this variable from list_snapshot – Tom Mu Nov 3 '15 at 6:13
  • Because it's out of take_snapshot's scope; functions can only see their local variables and global variables, not other function's variables. You should remove output=$(VBoxManage snapshot "$machine_name" list) from list_snapshot and initialize it outside of any function if you want all functions to be able to access it. – kos Nov 3 '15 at 6:16
1

You can't; variables declared / initialized in a function are only visible in that function's scope.

Also in your specific case, if you run ./script.sh MyVM take, list_snapshot() is not even run; how is output supposed to be declared / initialized (and how is old_snapshot_name supposed to be declared / initialized, since its declaration / initialization relies on output, which has not been declared / initialized?)

To make output visible to all the functions and regardless of which functions are actually run, move its declaration / initialization outside of list_snapshot(), for example after take_snapshot()'s definition:

#! /bin/sh

if [ ! "$1" ]; then
    echo "Usage: $0 <vmname> list|take"
    exit 1
else
    machine_name=$1
fi

list_snapshot () {
    count=$(echo "$output" | grep -c 'UUID')

    echo "Machine '$machine_name' has '$count' snapshots: \n '$output'"
    return "$count"
}


take_snapshot () {
    echo "$output"
    while (list_snapshot; [ $? -gt 3 ])  
    do
        old_snapshot_name=$(echo "$output" | grep -o 'UUID: (.{36})' | head -1)
        echo "Deleting old snapshot '$old_snapshot_name' for machine '$machine_name'..."

        VBoxManage snapshot "$machine_name" delete "$old_snapshot_name"

    done

    current_time=$(date "+%Y.%m.%d-%H.%M.%S")
    snapshot_name=$machine_name.$current_time

    echo "Taking new snapshot '$snapshot_name' for machine '$machine_name'..."
    VBoxManage snapshot "$machine_name" take "$snapshot_name" --live 
}

output=$(VBoxManage snapshot "$machine_name" list)

case "$2" in
  list)
    list_snapshot
    ;;
  take)
    take_snapshot
    ;;
  *)
    echo "Usage: $0 <vmname> list|take"
    exit 1
    ;;
esac
2
  • Thank you, looks like I meet some variable scope problem, , after redesign my code, remove while loop, now it works – Tom Mu Nov 3 '15 at 8:02
  • 1
    If the answer has helped you, accept the answer with a click on the check mark at the left side of the answer. ;) – A.B. Nov 3 '15 at 8:12

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.