Получить список запущенных ВМ с помощью VBoxManage

Я хочу перебирать мои работающие виртуальные машины и возвращать только то, что находится между кавычками.

Итак, эта команда:

VBoxManage list runningvms

возвращает:

"UbuntuServer" {7ef01f8d-a7d5-4405-af42-94d85f999dff}

И я только хочу, чтобы он вернулся:

UbuntuServer

Это то, что у меня есть до сих пор (сбой):

#!/bin/bash
for machine in `cat VBoxManage list runningvms`; do
        echo "$machine"
done
exit

person capdragon    schedule 15.08.2011    source источник


Ответы (5)


Предупреждение: все это рискованно, если в именах ваших виртуальных машин есть символы оболочки или пробелы.


Вы можете сделать что-то подобное, если есть только одна работающая виртуальная машина:

read machine stuff <<< $(VBoxManage list runningvms)
echo "$machine"

Альтернатива с массивами bash (то же условие):

vbm=($(VBoxManage list runningvms))
echo "${vbm[0]}"

Если эта программа возвращает более одной строки, более классическим подходом будет:

for machine in $(VBoxManage list runningvms|cut -d" " -f 1); do
  echo "$machine"
done
person Mat    schedule 15.08.2011
comment
Классический подход — это плохая практика, как и подход array=( $(...) ); оба, например, заменят один токен * в вашем вводе списком файлов в текущем каталоге. См. Не читать строки с For, BashPitfalls #50 и BashFAQ #1 - person Charles Duffy; 17.01.2018
comment
Для этого конкретного примера требуется разбиение слов, и имя виртуальной машины, совпадающее с шаблоном глобуса, кажется маловероятным. - person Mat; 17.01.2018
comment
Худшее событие потери данных, на котором я присутствовал, произошло из-за того, что кто-то проигнорировал невозможное событие (программа, создающая файлы, не могла когда-либо создать что-либо, не совпадающее с [0-9a-f]{24}; ошибка в стороннем библиотека повредила указатель, сбрасывая случайный мусор, который, как оказалось, включал *, окруженный пробелами, в буфер, используемый для имени... и сценарий оболочки, перебирающий имена файлов, чтобы они устарели, из системы резервного копирования, а затем удалял все). - person Charles Duffy; 17.01.2018
comment
Более того, практики, которым мы обучаем здесь, будут использоваться в другом месте и в других случаях - если в ответе нет большой оговорки, они должны быть безопасны для широкого и общего использования. - person Charles Duffy; 17.01.2018
comment
Хорошо. У меня сейчас нет возможности воспроизвести вывод этой команды, поэтому я не могу сделать идеальный ответ. Не стесняйтесь добавлять свои собственные. - person Mat; 17.01.2018
comment
re: тестируемость - см. функцию, издевающуюся над VBoxManage, включенную в мой ответ. - person Charles Duffy; 17.01.2018

для однострочных фанатов:

VBoxManage list runningvms | cut -d" " -f 1 | grep -oP "(?<=\").*(?=\")"
person Omriko    schedule 17.08.2016

Чтобы проверить каждую строку по мере ее чтения, безопасный способ сделать это — написать регулярное выражение и использовать BASH_REMATCH для извлечения из него групп совпадений.

Со следующим кодом:

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)

... и следующую фиктивную реализацию VBoxManage (чтобы люди без VirtualBox могли воспроизвести тест):

VBoxManage() { printf '%s\n' '"UbuntuServer" {7ef01f8d-a7d5-4405-af42-94d85f999dff}'; }

... вывод выглядит следующим образом:

Found VM with name UbuntuServer and uuid 7ef01f8d-a7d5-4405-af42-94d85f999dff

Обратите внимание на преимущества этого подхода:

  • Он не делает необоснованных предположений, таких как исключение из поддержки виртуальных машин с пробелами или кавычками в их именах.
  • Он обнаруживает любую строку, которая не соответствует ожидаемому шаблону, а не ведет себя непредвиденным образом при наличии таких значений.
  • Он по-прежнему корректно работает с данными, которые действительно соответствуют шаблону, но имеют непредвиденные значения. (Например, для виртуальной машины с именем * это имя не будет автоматически заменено именем файла в текущем каталоге).
  • Он не включает инструменты, внешние по отношению к оболочке, такие как sed, cut и т. д., а опирается исключительно на встроенную в оболочку функциональность -- см. BashFAQ #1, документирующий использование while read, и Вики bash-hackers по сопоставлению регулярных выражений документирует [[ $string =~ $re ]].
person Charles Duffy    schedule 17.01.2018

VBoxManage list runningvms | sed 's/"//g;s/ .*//'

Чтобы выполнить цикл:

for machine in `VBoxManage list runningvms | sed 's/"//g;s/ .*//'` ; do
    echo $machine
done

Это сломается, если в имени вашей машины есть пробелы.

person Shizzmo    schedule 15.08.2011

person    schedule
comment
Это лучше, чем у меня - у меня не получится, если в имени изображения есть пробелы... не думал об этом. - person Mat; 16.08.2011
comment
Синтаксис while read ... do — это именно то, что я искал! - person Kyrstellaine; 17.08.2017
comment
Вы можете убрать cut, написав while IFS='"' read _ machine _; do. - person Charles Duffy; 17.01.2018