I have a list of boxes and need to list only the outdated ones.
For example, input will look something like this:
maier/alpine-3.1.3-x86_64 (virtualbox, 1.2.0) maier/alpine-3.1.3-x86_64 (virtualbox, 1.3.0) ubuntu/precise64 (virtualbox, 20151202.0.0) ubuntu/vivid64 (virtualbox, 20150821.0.0) ubuntu/vivid64 (virtualbox, 20150903.0.0) ubuntu/vivid64 (virtualbox, 20151113.0.0) ubuntu/vivid64 (virtualbox, 20151127.0.0) ubuntu/vivid64 (virtualbox, 20151211.0.0) ubuntu/wily64 (virtualbox, 20151203.0.0)
Output will look roughly like this:
maier/alpine-3.1.3-x86_64 (virtualbox, 1.2.0) ubuntu/vivid64 (virtualbox, 20150821.0.0) ubuntu/vivid64 (virtualbox, 20150903.0.0) ubuntu/vivid64 (virtualbox, 20151113.0.0) ubuntu/vivid64 (virtualbox, 20151127.0.0)
Note the format consists of: name
, provider
, version
It seems like there would be an easy way to do this from Bash scripting alone, e.g. I can version sort a particular column with sort
, but I wasn't quite able to figure it out so I roughed it out in Python instead.
Is there are better way to do this?
#!/usr/bin/python3
# -*- coding: utf-8 -*-
"""Attempt to remove outdated Vagrant boxes"""
import os
import re
import subprocess
from distutils.version import StrictVersion
def search(text):
"""Return a dictionary containing all the named subgroups of the match."""
patt = r'^(?P<name>[^ ]+) +\((?P<provider>[^ ]+), +(?P<version>[^ ]+)\)$'
return re.search(patt, text).groupdict()
output = subprocess.check_output(['vagrant', 'box', 'list'],
stderr=subprocess.DEVNULL).decode().rstrip()
box_list = (search(line) for line in output.splitlines())
box_dict = {}
for box in box_list:
name = box.get('name')
version = box.get('version')
box_dict[name] = box_dict.get(name, []) + [version]
outdated_boxes = {}
for box in box_dict:
versions = box_dict[box]
# remove the most recent version
if len(versions) > 1:
outdated_boxes[box] = sorted(versions, key=StrictVersion)[:-1]
for box in outdated_boxes:
versions = outdated_boxes[box]
for version in versions:
command = ['vagrant', 'box', 'remove', box, '--box-version', version]
print(*command)
os.system(' '.join(command))
# process = subprocess.Popen(command)
# process.wait()
print()
1 Answer 1
Since everything is printed in order, the "obsolete" ones are all but the last version for the first word. That's tricky. But if we looked at the text backwards, we're printing all but the first one.
And that's easy with awk:
awk '!(1ドル in seen){print }{seen[1ドル] = 1}'
And then just invert the input twice:
run_your_version_cmd_here | tac | awk '1ドル not in seen{print }{seen[1ドル] = 1}' | tac
-
\$\begingroup\$ Awesome, thank you. I hadn't even realized the original text was in order. \$\endgroup\$Six– Six2015年12月11日 17:38:29 +00:00Commented Dec 11, 2015 at 17:38