5

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?

6
  • 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, 2020 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, 2020 at 14:15
  • Others using VirtualBox may find this question useful.
    – Jeff Schaller
    Jan 19, 2020 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, 2020 at 14:58
  • The same awk command would work in any shell: zsh, csh, fish, etc.
    – Jeff Schaller
    Jan 19, 2020 at 15:16

6 Answers 6

10

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

VBoxManage list vms | awk -F"[{}]" '/Test Machine/{print $2}' 
2
  • 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, 2020 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, 2020 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)}'
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.

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

output

9d0953a7-ca2a-4667-8c5b-1a9f550b2956
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'
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 :-)

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .