VMware Cloud Community
Named_Jason
Contributor
Contributor
Jump to solution

Question about scripting vmware-cmd actions on VMs with spaces in path

Hi - I'm trying to write a simple script (mostly to demonstrate ESX Host scripting) that simply does a vmware-cmd <vmx> getstate (or whatever command is passed upon execution) on all registered VMs on a given Host and am running into a problem; I cannot get vmware-cmd to ignore the special meaning of the spaces in the paths to a vmx file, when executing it from a script with a variable as input.

Here's my script:

vmware-cmd -l > /tmp/vmlist
for (( i = 1 ; i <= `wc -l /tmp/vmlist | awk '{print $1}'` ; i++ ))
do
pathToVMX=`head -n $i /tmp/vmlist | tail -n 1`
echo $pathToVMX
vmware-cmd $pathToVMX $1
done
rm -f /tmp/vmlist

It works great on VMs that do not have spaces in their names, behaving exactly as I'd expect. I have not been able to get it to ignore the special meaning of the space no matter what I've tried though. I've tried encapsulating the path in both strong and weak quotes (sed -i 's/$/\"/;s/^/\"/' /tmp/vmlist) as well as using slashes prior to every space in the file (sed -i 's/\ /
\ /g' /tmp/vmlist), however neither one works. Curious about what's going on here, I changed my line from executing the command directly (vmware-cmd $pathToVMX $1) to outputting the command that it was executing (echo vmware-cmd $pathToVMX $1) and then copied the output and pasted it as a command - and it worked flawlessly (I did the test on the quotes method), ignoring the special meaning of the spaces in the file path. The problem seems to be related to dereferencing the variable directly by the command; does anyone know an elegant workaround?

The best that I've been able to come up with is to echo the output to a file, make the file executable, execute the file, then delete the file. It seems like there's got to be a better way to work around this, and I'm fairly certain that I'm just overlooking something that's remarkably simple. Does anyone have any ideas? Thanks.

Reply
0 Kudos
1 Solution

Accepted Solutions
lamw
Community Manager
Community Manager
Jump to solution

#!/bin/sh

IFS=$'\n'

for i in `vmware-cmd -l`;

do

NAME=`vmware-cmd "$" getconfig displayName | awk '{print $3}'` STATE=`vmware-cmd "$" getstate | awk '{print $3}'`

echo "VM: $ State is $"

done

unset IFS

I also just verified this on a 3.x host to make sure my syntax was correct, last time I posted this code was from memory.

View solution in original post

Reply
0 Kudos
5 Replies
Named_Jason
Contributor
Contributor
Jump to solution

You know how it is when you get some food and then come back to your work... well, I figured out a solution to this... and as predicted, it is embarassingly simple.

vmware-cmd -l > /tmp/vmlist
for (( i = 1 ; i <= `wc -l /tmp/vmlist | awk '{print $1}'` ; i++ ))
do
pathToVMX=`head -n $i /tmp/vmlist | tail -n 1`
echo $pathToVMX
vmware-cmd "$pathToVMX" $1
done
rm -f /tmp/vmlist

For those who don't want to go digging through that code looking for the difference, all that I did was add " marks around the variable name when calling vmware-cmd instead of putting the quotes inside the variable:

ie. vmware-cmd "$variable" getstate

works when $variable = /vmfs/volumes/LUN/path to config.vmx

whereas vmware-cmd $variable getstate

does not work when $variable = "/vmfs/volumes/LUN/path to config.vmx"

Reply
0 Kudos
lamw
Community Manager
Community Manager
Jump to solution

Yea, it's fun when you have spaces, special characters, etc. You can also redefine the IFS deliminter to 'newline' which has been a recommednation when looping through the VMs.

You can also clean up your script with the following:

#!/bin/sh

for i in `vmware-cmd -l`;

do

NAME=`vmware-cmd "$" getConfig displayName | awk '{print $3}'` STATE=`vmware-cmd "$" getstate | awk '{print $3}'

echo "VM: $ State is $"

done

You'll want to verify the getConfig, I'm going off of memory, don't have access to a console at the moment but it should be getconfig or getvariable.

Named_Jason
Contributor
Contributor
Jump to solution

Thanks for your help so far - how do you change the IFS delimiter to 'newline'?

I googled it and came up with entering this line near the top of the script:

IFS=\n

Unfortunately, that seems to make the 'n' character the delimiter, rather than the new line. Some more research directed me at \x0a and \012 with no solutions. Any other suggestions? Thanks.

p.s. here's the current version of my script - thank you for the suggestions already posted:

#!/bin/sh

IFS=\x0a

for pathToVMX in `vmware-cmd -l`;

do

echo $pathToVMX

vmware-cmd $pathToVMX $1

done

Reply
0 Kudos
lamw
Community Manager
Community Manager
Jump to solution

#!/bin/sh

IFS=$'\n'

for i in `vmware-cmd -l`;

do

NAME=`vmware-cmd "$" getconfig displayName | awk '{print $3}'` STATE=`vmware-cmd "$" getstate | awk '{print $3}'`

echo "VM: $ State is $"

done

unset IFS

I also just verified this on a 3.x host to make sure my syntax was correct, last time I posted this code was from memory.

Reply
0 Kudos
Named_Jason
Contributor
Contributor
Jump to solution

the $'\n' worked perfectly for me, thank you very much for your help with this (as well as your excellent formatting of the output 😃

Reply
0 Kudos