3

I'm attempting to write a bash function that gets the UUID of a VirtualBox VM. I'm pretty new to awk so I'm trying to focus on learning how to solve the problem using it. I'm aware that I can use sed or even cut to solve this.

My "raw" output from the VBoxManage list vms is as follows:

$ VBoxManage list vms
"FreeBSD" {1aac7062-bd59-47ee-9261-2f6aa8d9ef53}
"Windows 10" {64942de7-beb9-418c-9f52-5befcb6f577b}
"High Sierra" {07f73e1a-a0c4-4190-ade1-79a2e432b4d6}
"Test Machine" {9d0953a7-ca2a-4667-8c5b-1a9f550b2956}

My desired output is to just get the UUID of a particular VM. Using "Test Machine" for this case, I'm looking for 9d0953a7-ca2a-4667-8c5b-1a9f550b2956 (without the brackets { and }).

After quite a bit of searching and testing, I've come up with

$ VBoxManage list vms | awk '/Test Machine/{ sub("{" ,""); sub("}", "");  print $3 }'

9d0953a7-ca2a-4667-8c5b-1a9f550b2956 

It works, but I have to use to sub commands to extract it.


My question is, is there a way to simplify the substitution portion of the action with an or type operator so I don't have to use two sub commands?

For example, if I try awk '/Test Machine/{ sub("{" || "}", ""); print $3' it doesn't work - it prints the whole field including the brackets.

 {9d0953a7-ca2a-4667-8c5b-1a9f550b2956}

Is there a better way of extracting that string?

  • Allan, I've adjusted the tags to reflect Virtualbox being involved and bash not being involved in your question, since you're asking about awk code specifically regarding extracting a UUID from a virtualbox VM list. – Jeff Schaller Jan 19 at 13:25
  • @JeffSchaller - VirtualBox has nothing to do with this question other than providing the string I want to parse with awk in a script written and running in bash. You have this completely backwards. Rolling back. – Allan Jan 19 at 14:15
  • Others using VirtualBox may find this question useful. – Jeff Schaller Jan 19 at 14:53
  • @JeffSchaller... They may but it's not a VB question. That said, I can (partially) see that argument for adding the tag but not removing the bash tag. In the end, this is about parsing a string using awk in bash running on macOS. The string just happens to come from VB. – Allan Jan 19 at 14:58
  • The same awk command would work in any shell: zsh, csh, fish, etc. – Jeff Schaller Jan 19 at 15:16
7

-F field separator in awk. Here we are using 2 field separators. (either { or } )

VBoxManage list vms | awk -F"[{}]" '/Test Machine/{print $2}' 
|improve this answer|||||
  • I went with this answer because it appears to be the most efficient and elegant without piping to another utility like grep, sed or others. This works beautifully and I learned something (new) about field separators that wasn't in the "tutorials" I found on the internet. – Allan Jan 17 at 15:33
  • It might fail if there is/are vms that has { or } on their name. I know It's highly unlikely but It could happen... – Jetchisel Jan 18 at 8:41
3

Another way.

VBoxManage list vms | awk -F ' ' '{print substr($2, 2, length($2) - 2)}'

Separate fields by empty space

awk -F ' '

Print second column removing the first { and last } characters

'{print substr($2, 2, length($2) - 2)}'
|improve this answer|||||
2

With Gnu grep (uses Perl-stye regex):

grep -Po "(?<={)[a-f0-9-]+(?=})" 

... in other words, any sequence of hex digits and dash, occurring after an opening brace and immediately followed by a closing one.

With plain grep

grep -Eo "([a-f0-9-]+-){4}[a-f0-9-]+"

... ie, 5 groups of hex digits separated by dashes.

|improve this answer|||||
0
  VBoxManage list vms|  awk -F "{" '/Test Machine/{gsub("}","",$NF);print $NF}'

output

9d0953a7-ca2a-4667-8c5b-1a9f550b2956
|improve this answer|||||
0
$ VBoxManage showvminfo 'Test Machine' --machinereadable | sed -n '/^UUID=/{ s///; s/"//gp; }'
1ce7ffef-8faa-4138-9b92-466698762f62

Instead of using the list vms sub-command, this uses the sub-command showvminfo, which gets all the information for a particular machine (here a VM called Test Machine). With --machinereadable, this outputs the data in a form that is easily parseable. The VMs UUID will be outputted like

UUID="1ce7ffef-8faa-4138-9b92-466698762f62"

which the sed command detects. It removes the UUID= bit and all double quotes and then prints whatever is left.

The sed command could be written in multiple different ways. A variation is for example,

sed -n 's/^UUID="\(.*\)"$/\1/p'
|improve this answer|||||
0

Here is how I would do it using P.E. and bash syntax.

while read -r vmname uuid; do
  uuid=${uuid##*'{'}
  uuid=${uuid%'}'*}
  vmname=${vmname#*'"'}
  vmname=${vmname%'"'*}
  printf '%-15s %s\n' "$vmname" "$uuid"
done < <(VBoxManage list vms)

You can start the vms inside the loop with a match using a test or save the output in array and so on. It should also be safe even if the vm name has a { or } in it's name. I've been using that code in my script since 2013 :-)

|improve this answer|||||

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.