Get a list of running VMs using VBoxManage
I want to loop through my running VM's and return only what is between quotes.
So this command:
VBoxManage list runningvms
returns:
"UbuntuServer" {7ef01f8d-a7d5-4405-af42-94d85f999dff}
And I only want it to return开发者_如何学Go:
UbuntuServer
This is what i have so far (fail):
#!/bin/bash
for machine in `cat VBoxManage list runningvms`; do
echo "$machine"
done
exit
VBoxManage list runningvms | cut -d '"' -f 2 | while read machine; do
echo "$machine"
done
Warning: all of this is is risky if your VM names have shell glob characters in them, or contain spaces.
You can do something like this if there is only one running VM:
read machine stuff <<< $(VBoxManage list runningvms)
echo "$machine"
Alternative with bash arrays (same condition):
vbm=($(VBoxManage list runningvms))
echo "${vbm[0]}"
If that program returns more than one line, a more classic approach would be:
for machine in $(VBoxManage list runningvms|cut -d" " -f 1); do
echo "$machine"
done
for one-liner fans:
VBoxManage list runningvms | cut -d" " -f 1 | grep -oP "(?<=\").*(?=\")"
To validate each line as you read it, the safe way to do this is to write a regular expression and use BASH_REMATCH
to extract match groups from it.
With the following code:
re='^"(.*)" [{]([0-9a-f-]+)[}]$'
while read -r line; do
if [[ $line =~ $re ]]; then
name=${BASH_REMATCH[1]}; uuid=${BASH_REMATCH[2]}
echo "Found VM with name $name and uuid $uuid" >&2
else
echo "ERROR: Could not parse line: $line" >&2
fi
done < <(VBoxManage list runningvms)
...and the following mock implementation of VBoxManage (to allow folks without VirtualBox to reproduce the test):
VBoxManage() { printf '%s\n' '"UbuntuServer" {7ef01f8d-a7d5-4405-af42-94d85f999dff}'; }
...output is as follows:
Found VM with name UbuntuServer and uuid 7ef01f8d-a7d5-4405-af42-94d85f999dff
Note advantages of this approach:
- It doesn't make unfounded assumptions, such as excluding virtual machines with whitespace or quote literals in their names from support.
- It detects any line that doesn't match the expected pattern, rather than behaving in an unanticipated way in the presence of such values.
- It still behaves correctly with data that does match the pattern but has unanticipated values. (For instance, a virtual machine named
*
won't have that name silently replaced with the name of a file in the current directory). - It doesn't involve tools external to the shell such as
sed
,cut
, &c., but relies purely on shell-builtin functionality -- see BashFAQ #1 documenting the use ofwhile read
, and the bash-hackers' wiki on regular expression matching documenting[[ $string =~ $re ]]
.
VBoxManage list runningvms | sed 's/"//g;s/ .*//'
To loop through:
for machine in `VBoxManage list runningvms | sed 's/"//g;s/ .*//'` ; do
echo $machine
done
This will break if your machine has spaces in its name.
VBoxManage list runningvms|awk -F \{ '{gsub("\"",""); print $1}'
For each line in the output of VBoxManage
, this strips out the "
characters, and then prints the first field (when using {
as the field separator, which starts the UID of the vbox vm).
There is no need to check for spaces or handle any part of the output differently, or do any shell manipulations other than escaping special characters.
I find awk to be more versatile than cut
,grep
,sed
, and so on, and it's more expressive too. It's been around since 1987 and a POSIX standard since 1992: you're more likely to have awk
on your system than bash
.
精彩评论