3
\$\begingroup\$

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()
Quill
12k5 gold badges41 silver badges93 bronze badges
asked Dec 11, 2015 at 16:46
\$\endgroup\$

1 Answer 1

2
\$\begingroup\$

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
answered Dec 11, 2015 at 17:25
\$\endgroup\$
1
  • \$\begingroup\$ Awesome, thank you. I hadn't even realized the original text was in order. \$\endgroup\$ Commented Dec 11, 2015 at 17:38

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.