diff --git a/fsl/utils/filetree/filetree.py b/fsl/utils/filetree/filetree.py
index 6f268b27d572408aebcf51c3ebb0df277cb9c37a..c7d7bcf4d65e136e3f88504eff7ee23208722799 100644
--- a/fsl/utils/filetree/filetree.py
+++ b/fsl/utils/filetree/filetree.py
@@ -20,7 +20,7 @@ class FileTree(object):
 
     Properties
     - ``templates``: dictionary mapping short names to filename templates
-    - ``variables``: dictionary mapping variables in the templates to specific values
+    - ``variables``: dictionary mapping variables in the templates to specific values (variables set to None are explicitly unset)
     - ``sub_trees``: filename trees describing specific sub-directories
     - ``parent``: parent FileTree, of which this sub-tree is a sub-directory
     """
@@ -182,6 +182,7 @@ class FileTree(object):
         Creates a new filetree with updated variables
 
         :arg variables: new values for the variables
+        Setting variables to None will explicitly unset them
         """
         new_tree = deepcopy(self)
         new_tree.variables.update(variables)
@@ -194,6 +195,7 @@ class FileTree(object):
         :param short_name: short name of the path template
         :param filename: filename matching the template
         :return: variables needed to get to the given filename
+        Variables with None value are optional variables in the template that were not used
         """
         text, _ = self.get_template(short_name)
         return utils.extract_variables(text, filename, self.variables)
diff --git a/fsl/utils/filetree/utils.py b/fsl/utils/filetree/utils.py
index 54cdc3c5d9324883a0aa66455f9a22fe8a78cce6..f78046fff8f6878309225b55ae22d6c8dab519ff 100644
--- a/fsl/utils/filetree/utils.py
+++ b/fsl/utils/filetree/utils.py
@@ -65,14 +65,18 @@ def fill_known(template, variables):
     Fills in the known variables filling the other variables with {<variable_name>}
 
     :param template: template
-    :param variables: mapping of variable names to values
+    :param variables: mapping of variable names to values (ignoring any None)
     :return: cleaned string
     """
     prev = ''
     while prev != template:
         prev = template
-        settings = {name: variables[name] if name in variables else '{' + name + '}'
-                    for name in set(find_variables(template))}
+        settings = {}
+        for name in set(find_variables(template)):
+            if name in variables and variables[name] is not None:
+                settings[name] = variables[name]
+            else:
+                settings[name] = '{' + name + '}'
         template = template.format(**settings)
     return template
 
@@ -135,7 +139,7 @@ def extract_variables(template, filename, known_vars=None):
     :param template: template matching the given filename
     :param filename: filename
     :param known_vars: already known variables
-    :return: dictionary from variable names to string representations
+    :return: dictionary from variable names to string representations (unused variables set to None)
     """
     if known_vars is None:
         known_vars = {}
@@ -166,6 +170,9 @@ def extract_variables(template, filename, known_vars=None):
                     raise ValueError('Multiple values found for {}'.format(var))
             else:
                 extracted_value[var] = value
+        for name in find_variables(template):
+            if name not in extracted_value:
+                extracted_value[name] = None
         extracted_value.update(known_vars)
         return extracted_value
     raise ValueError("{} did not match {}".format(filename, template))
diff --git a/tests/test_filetree/test_read.py b/tests/test_filetree/test_read.py
index 17cbe01145c477ea05340fd60b6801d4acc244dd..b27984477218cd69f757199948865c2a06e6f8d1 100644
--- a/tests/test_filetree/test_read.py
+++ b/tests/test_filetree/test_read.py
@@ -76,6 +76,9 @@ def test_custom_tree():
     assert len(tree.get_all('sub_file', glob_vars=['opt'])) == 2
     assert len(tree.get_all('sub_file', glob_vars='all')) == 2
     assert len(tree.get_all('sub_file')) == 1
+    assert len(tree.update(opt=None).get_all('sub_file')) == 1
+    assert len(tree.update(opt=None).get_all('sub_file', glob_vars=['opt'])) == 1
+    assert len(tree.update(opt=None).get_all('sub_file', glob_vars='all')) == 1
 
     for fn, settings in zip(tree.get_all('sub_file', glob_vars='all'),
                             tree.get_all_vars('sub_file', glob_vars='all')):
@@ -87,9 +90,10 @@ def test_custom_tree():
         tree.get_all('opt_file')
     assert len(tree.get_all('opt_file', glob_vars=['opt'])) == 1
 
-    for vars in ({}, {'opt': 'test'}):
+    for vars in ({'opt': None}, {'opt': 'test'}):
         filename = tree.update(**vars).get('sub_file')
         assert vars == tree.extract_variables('sub_file', filename)
+    assert {'opt': None} == tree.extract_variables('sub_file', tree.get('sub_file'))
 
     assert tree.exists(('sub_file', 'opt_file'), error=True, on_disk=True, glob_vars=['opt'])
     assert tree.exists(('sub_file', 'opt_file'), on_disk=True, glob_vars=['opt'])
diff --git a/tests/test_filetree/test_template.py b/tests/test_filetree/test_template.py
index ad572a48e0c80772ac78338f84cf01878074af65..96ecc18f00adb1add2b191c8d3744460f1c02bc6 100644
--- a/tests/test_filetree/test_template.py
+++ b/tests/test_filetree/test_template.py
@@ -11,10 +11,10 @@ def test_variables():
 def test_get_variables():
     assert {'var': 'test'} == utils.extract_variables('{var}', 'test')
     assert {'var': 'test'} == utils.extract_variables('2{var}', '2test')
-    assert {'var': 'test'} == utils.extract_variables('{var}[_{other_var}]', 'test')
+    assert {'var': 'test', 'other_var': None} == utils.extract_variables('{var}[_{other_var}]', 'test')
     assert {'var': 'test', 'other_var': 'foo'} == utils.extract_variables('{var}[_{other_var}]', 'test_foo')
     assert {'var': 'test', 'other_var': 'foo'} == utils.extract_variables('{var}[_{other_var}]_{var}', 'test_foo_test')
-    assert {'var': 'test'} == utils.extract_variables('{var}[_{other_var}]_{var}', 'test_test')
+    assert {'var': 'test', 'other_var': None} == utils.extract_variables('{var}[_{other_var}]_{var}', 'test_test')
     with pytest.raises(ValueError):
         utils.extract_variables('{var}[_{other_var}]_{var}', 'test_foo')
     with pytest.raises(ValueError):