# Python script to touch files of a particular pattern in all folders of a given name

The intent of this script is to hunt down all "*/testResults/*.xml" files and touch them, so that our build system doesn't issue errors that the files are too old (it's entirely intentional that tests are only re-run when the libraries they change have been modified)

import fnmatch
import os
import time

matches = []

# Find all xml files  (1)
for root, dirnames, filenames in os.walk('.'):
for filename in fnmatch.filter(filenames, '*.xml'):
matches.append(os.path.join(root, filename))

# filter to only the ones in a "/testResults/" folder  (2)
tests = [k for k in matches if "\\testResults\\" in k]

t = time.time()

# touch them
for test in tests:
os.utime(test,(t,t))


Is there a simpler way to achieve this? Specifically to perform steps (1) and (2) in a single process, rather than having to filter the matches array? An alternative solution would be to just recursively find all folders called "/testResults/" and list the files within them.

Notes:

• This script would also find "blah/testResults/blah2/result.xml" - I'm not worried about that, as the testResults folders will only contain test result xml files (but not all xml files are test results!)

• This runs on Windows.

• I don't think recursion is a good solution for this problem at all. You're initial solution is better. – James Khoury Jan 30 '14 at 1:22
• I meant recursively in a filesystem sense (i.e. it could be /a/testResults/ or /a/b/testResults/ etc), not in a recursive function sense. – benjymous Jan 30 '14 at 9:13

## 3 Answers

For combining (1) and (2) you can reverse the sort by only trying if your are under a test directory

Also this is a great use for a generator / map combo to avoid extra loops

import os
import re

is_xml = re.compile('xml', re.I)
is_test = re.compile('testResults', re.I)

def find_xml_tests(root):
for current, dirnames, filenames in os.walk(root):
if is_test.search(current):
for filename in filter(lambda p: is_xml.search(p),  filenames):
yield  os.path.normpath(os.path.join(current, filename))

def touch(filename ):
os.utime(test,(time.time(),time.time()))

map(touch, find_xml_tests('path/to/files'))


Python seems like overkill here: this is surely a job for the shell? Depending on exactly which files you want to touch, then use this:

touch -- */testResults/*.xml


or this:

find . -path '*/testResults/*.xml' -exec touch -- {} \+


You indicated that you are using Windows. But even on Windows, surely a PowerShell script (using Get-ChildItem instead of find and Set-ItemProperty -Name LastWriteTime instead of touch) would be simplest?

• Yes, Windows I'm afraid! – benjymous Jan 29 '14 at 16:06
• I've updated your question accordingly. – Gareth Rees Jan 29 '14 at 16:08
import os,glob,time
t = time.time()
def touchy(fpath):
os.utime(fpath,(t,t))
return fpath

def findResults(directory = "/"):
results = []
search_path = os.path.join(directory,"testResults/*.xml")
for d in filter(os.path.isdir,os.listdir(directory)):
results.extend( map(touchy,glob.glob(search_path)) if d == "testResults" else findResults(os.path.join(directory,d))
return results


is probably about the best you can do if you want python

• Can you revise this to avoid the long line? – Gareth Rees Jan 29 '14 at 18:09
• there its shorter lines ... still probably not quite pep-8 – Joran Beasley Jan 29 '14 at 18:12