diff --git a/xUnique.py b/xUnique.py
index 9cd6890..5f46ad1 100755
--- a/xUnique.py
+++ b/xUnique.py
@@ -19,23 +19,25 @@
 """
 
 from __future__ import unicode_literals
+from __future__ import print_function
 from subprocess import (check_output as sp_co, check_call as sp_cc)
 from os import path, unlink, rename
 from hashlib import md5 as hl_md5
-import json
+from json import loads as json_loads
 from urllib import urlretrieve
 from fileinput import (input as fi_input, close as fi_close)
 from re import compile as re_compile
 from sys import (argv as sys_argv, getfilesystemencoding as sys_get_fs_encoding)
 from collections import deque
 from filecmp import cmp as filecmp_cmp
+from optparse import OptionParser
 
 
 md5_hex = lambda a_str: hl_md5(a_str.encode('utf-8')).hexdigest().upper()
 
 
 class XUnique(object):
-    def __init__(self, xcodeproj_path):
+    def __init__(self, xcodeproj_path, verbose=False):
         # check project path
         abs_xcodeproj_path = path.abspath(xcodeproj_path)
         if not path.exists(abs_xcodeproj_path):
@@ -48,11 +50,13 @@ def __init__(self, xcodeproj_path):
             self.xcodeproj_path = path.split(self.xcode_pbxproj_path)[0]
         else:
             raise SystemExit("Path must be dir '.xcodeproj' or file 'project.pbxproj'")
+        self.vprint = print if verbose else lambda *a, **k: None
         self.proj_root = path.basename(self.xcodeproj_path)  # example MyProject.xpbproj
         self.proj_json = self.pbxproj_to_json()
         self.nodes = self.proj_json['objects']
         self.root_hex = self.proj_json['rootObject']
         self.root_node = self.nodes[self.root_hex]
+        self.main_group_hex = self.root_node['mainGroup']
         self.__result = {}
         # initialize root content
         self.__result.update(
@@ -66,7 +70,7 @@ def __init__(self, xcodeproj_path):
     def pbxproj_to_json(self):
         pbproj_to_json_cmd = ['plutil', '-convert', 'json', '-o', '-', self.xcode_pbxproj_path]
         json_unicode_str = sp_co(pbproj_to_json_cmd).decode(sys_get_fs_encoding())
-        return json.loads(json_unicode_str)
+        return json_loads(json_unicode_str)
 
     def __set_to_result(self, parent_hex, current_hex, current_path_key):
         current_node = self.nodes[current_hex]
@@ -88,8 +92,14 @@ def __set_to_result(self, parent_hex, current_hex, current_path_key):
         })
 
     def unique_pbxproj(self):
-        """
-        iterate all nodes in pbxproj file:
+        """"""
+        # with open(path.join(self.xcodeproj_path),'w') as result_file:
+        # json.dump(self.__result,result_file)
+        self.unique_project()
+        self.sort_pbxproj()
+
+    def unique_project(self):
+        """iterate all nodes in pbxproj file:
 
         PBXProject
         XCConfigurationList
@@ -107,20 +117,18 @@ def unique_pbxproj(self):
         PBXVariantGroup
         """
         self.__unique_project(self.root_hex)
-        # with open(path.join(self.xcodeproj_path),'w') as result_file:
-        # json.dump(self.__result,result_file)
         self.replace_uuids_with_file()
-        self.sort_pbxproj()
+
 
     def replace_uuids_with_file(self):
-        print 'replace UUIDs and remove unused UUIDs'
+        self.vprint('replace UUIDs and remove unused UUIDs')
         uuid_ptn = re_compile('(?<=\s)[0-9A-F]{24}(?=[\s;])')
         for line in fi_input(self.xcode_pbxproj_path, backup='.bak', inplace=1):
             # project.pbxproj is an utf-8 encoded file
             line = line.decode('utf-8')
             uuid_list = uuid_ptn.findall(line)
             if not uuid_list:
-                print line.encode('utf-8'),
+                print(line.encode('utf-8'), end='')
             else:
                 new_line = line
                 # remove line with non-existing element
@@ -130,9 +138,16 @@ def replace_uuids_with_file(self):
                 else:
                     for uuid in uuid_list:
                         new_line = new_line.replace(uuid, self.__result[uuid]['new_key'])
-                    print new_line.encode('utf-8'),
+                    print(new_line.encode('utf-8'), end='')
         fi_close()
-        unlink(self.xcode_pbxproj_path + '.bak')
+        tmp_path = self.xcode_pbxproj_path + '.bak'
+        if filecmp_cmp(self.xcode_pbxproj_path, tmp_path, shallow=False):
+            unlink(self.xcode_pbxproj_path)
+            rename(tmp_path, self.xcode_pbxproj_path)
+            print('Ignore uniquify, no changes made to', self.xcode_pbxproj_path)
+        else:
+            unlink(tmp_path)
+            print('Uniquify done')
 
     def sort_pbxproj_pl(self):
         """
@@ -146,7 +161,7 @@ def sort_pbxproj_pl(self):
         """
         sort_script_path = path.join(path.dirname(path.abspath(__file__)), 'sort-Xcode-project-file-mod2.pl')
         if not path.exists(sort_script_path):
-            print 'downloading sort-Xcode-project-file'
+            self.vprint('downloading sort-Xcode-project-file')
             f_path, http_msgs = urlretrieve(
                 'https://raw.githubusercontent.com/truebit/webkit/master/Tools/Scripts/sort-Xcode-project-file',
                 filename=sort_script_path)
@@ -154,21 +169,22 @@ def sort_pbxproj_pl(self):
                 raise SystemExit(
                     'Cannot download script file from "https://raw.githubusercontent.com/truebit/webkit/master/Tools/Scripts/sort-Xcode-project-file"')
             for line in fi_input(sort_script_path, inplace=1, backup='.bak'):
-                print line.replace('{24}', '{32}'),
+                print(line.replace('{24}', '{32}'), end='')
             fi_close()
             unlink(sort_script_path + '.bak')
-        print 'sort project.xpbproj file'
+        self.vprint('sort project.xpbproj file')
         sp_cc(['perl', sort_script_path, self.xcode_pbxproj_path])
 
     def sort_pbxproj(self):
-        print 'sort project.xpbproj file'
+        self.vprint('sort project.xpbproj file')
+        uuid_chars = len(self.main_group_hex)
         lines = []
         files_start_ptn = re_compile('^(\s*)files = \(\s*$')
-        files_key_ptn = re_compile('(?<=[A-F0-9]{32} \/\* ).+?(?= in )')
+        files_key_ptn = re_compile('(?<=[A-F0-9]{{{}}} \/\* ).+?(?= in )'.format(uuid_chars))
         fc_end_ptn = '\);'
         files_flag = False
         children_start_ptn = re_compile('^(\s*)children = \(\s*$')
-        children_pbx_key_ptn = re_compile('(?<=[A-F0-9]{32} \/\* ).+?(?= \*\/)')
+        children_pbx_key_ptn = re_compile('(?<=[A-F0-9]{{{}}} \/\* ).+?(?= \*\/)'.format(uuid_chars))
         child_flag = False
         pbx_start_ptn = re_compile('^.*Begin (PBXBuildFile|PBXFileReference) section.*$')
         pbx_end_ptn = ('^.*End ', ' section.*$')
@@ -196,7 +212,7 @@ def file_dir_cmp(x, y):
             # files search and sort
             files_match = files_start_ptn.search(line)
             if files_match:
-                print line,
+                print(line, end='')
                 files_flag = True
                 if isinstance(fc_end_ptn, unicode):
                     fc_end_ptn = re_compile(files_match.group(1) + fc_end_ptn)
@@ -204,7 +220,7 @@ def file_dir_cmp(x, y):
                 if fc_end_ptn.search(line):
                     if lines:
                         lines.sort(key=lambda file_str: files_key_ptn.search(file_str).group())
-                        print ''.join(lines).encode('utf-8'),
+                        print(''.join(lines).encode('utf-8'), end='')
                         lines = []
                     files_flag = False
                     fc_end_ptn = '\);'
@@ -213,16 +229,17 @@ def file_dir_cmp(x, y):
             # children search and sort
             children_match = children_start_ptn.search(line)
             if children_match:
-                print line,
+                print(line, end='')
                 child_flag = True
                 if isinstance(fc_end_ptn, unicode):
                     fc_end_ptn = re_compile(children_match.group(1) + fc_end_ptn)
             if child_flag:
                 if fc_end_ptn.search(line):
                     if lines:
-                        if self.__result[self.__main_group_hex]['new_key'] not in last_two[0]:
-                            lines.sort(key=lambda file_str: children_pbx_key_ptn.search(file_str).group(),cmp=file_dir_cmp)
-                        print ''.join(lines).encode('utf-8'),
+                        if self.main_group_hex not in last_two[0]:
+                            lines.sort(key=lambda file_str: children_pbx_key_ptn.search(file_str).group(),
+                                       cmp=file_dir_cmp)
+                        print(''.join(lines).encode('utf-8'), end='')
                         lines = []
                     child_flag = False
                     fc_end_ptn = '\);'
@@ -231,7 +248,7 @@ def file_dir_cmp(x, y):
             # PBX search and sort
             pbx_match = pbx_start_ptn.search(line)
             if pbx_match:
-                print line,
+                print(line, end='')
                 pbx_flag = True
                 if isinstance(pbx_end_ptn, tuple):
                     pbx_end_ptn = re_compile(pbx_match.group(1).join(pbx_end_ptn))
@@ -239,7 +256,7 @@ def file_dir_cmp(x, y):
                 if pbx_end_ptn.search(line):
                     if lines:
                         lines.sort(key=lambda file_str: children_pbx_key_ptn.search(file_str).group())
-                        print ''.join(lines).encode('utf-8'),
+                        print(''.join(lines).encode('utf-8'), end='')
                         lines = []
                     pbx_flag = False
                     pbx_end_ptn = ('^.*End ', ' section.*')
@@ -247,28 +264,28 @@ def file_dir_cmp(x, y):
                     lines.append(line)
             # normal output
             if not (files_flag or child_flag or pbx_flag):
-                print line,
+                print(line, end='')
         fi_close()
         tmp_path = self.xcode_pbxproj_path + '.bak'
         if filecmp_cmp(self.xcode_pbxproj_path, tmp_path, shallow=False):
             unlink(self.xcode_pbxproj_path)
-            rename(tmp_path,self.xcode_pbxproj_path)
-            print 'Ignore, no changes made to {}'.format(self.xcode_pbxproj_path)
+            rename(tmp_path, self.xcode_pbxproj_path)
+            print('Ignore sort, no changes made to', self.xcode_pbxproj_path)
         else:
-            unlink(self.xcode_pbxproj_path + '.bak')
+            unlink(tmp_path)
+            print('Sort done')
 
     def __unique_project(self, project_hex):
         '''PBXProject. It is root itself, no parents to it'''
-        print 'uniquify PBXProject'
-        print 'uniquify PBXGroup and PBXFileRef'
-        self.__main_group_hex = self.root_node['mainGroup']
-        self.__unique_group_or_ref(project_hex, self.__main_group_hex)
-        print 'uniquify XCConfigurationList'
+        self.vprint('uniquify PBXProject')
+        self.vprint('uniquify PBXGroup and PBXFileRef')
+        self.__unique_group_or_ref(project_hex, self.main_group_hex)
+        self.vprint('uniquify XCConfigurationList')
         bcl_hex = self.root_node['buildConfigurationList']
         self.__unique_build_configuration_list(project_hex, bcl_hex)
         subprojects_list = self.root_node.get('projectReferences')
         if subprojects_list:
-            print 'uniquify Subprojects'
+            self.vprint('uniquify Subprojects')
             for subproject_dict in subprojects_list:
                 product_group_hex = subproject_dict['ProductGroup']
                 project_ref_parent_hex = subproject_dict['ProjectRef']
@@ -282,7 +299,7 @@ def __unique_build_configuration_list(self, parent_hex, build_configuration_list
         cur_path_key = 'defaultConfigurationName'
         self.__set_to_result(parent_hex, build_configuration_list_hex, cur_path_key)
         build_configuration_list_node = self.nodes[build_configuration_list_hex]
-        print 'uniquify XCConfiguration'
+        self.vprint('uniquify XCConfiguration')
         for build_configuration_hex in build_configuration_list_node['buildConfigurations']:
             self.__unique_build_configuration(build_configuration_list_hex, build_configuration_hex)
 
@@ -293,7 +310,7 @@ def __unique_build_configuration(self, parent_hex, build_configuration_hex):
 
     def __unique_target(self, parent_hex, target_hex):
         '''PBXNativeTarget'''
-        print 'uniquify PBXNativeTarget'
+        self.vprint('uniquify PBXNativeTarget')
         cur_path_key = ('productName', 'name')
         self.__set_to_result(parent_hex, target_hex, cur_path_key)
         current_node = self.nodes[target_hex]
@@ -314,7 +331,7 @@ def __unique_target_dependency(self, parent_hex, target_dependency_hex):
 
     def __unique_container_item_proxy(self, parent_hex, container_item_proxy_hex):
         '''PBXContainerItemProxy'''
-        print 'uniquify PBXContainerItemProxy'
+        self.vprint('uniquify PBXContainerItemProxy')
         self.__set_to_result(parent_hex, container_item_proxy_hex, 'remoteInfo')
         cur_path = self.__result[container_item_proxy_hex]['path']
         current_node = self.nodes[container_item_proxy_hex]
@@ -333,12 +350,12 @@ def __unique_container_item_proxy(self, parent_hex, container_item_proxy_hex):
 
     def __unique_build_phase(self, parent_hex, build_phase_hex):
         '''PBXSourcesBuildPhase PBXFrameworksBuildPhase PBXResourcesBuildPhase PBXCopyFilesBuildPhase'''
-        print 'uniquify PBXSourcesBuildPhase, PBXFrameworksBuildPhase and PBXResourcesBuildPhase'
+        self.vprint('uniquify PBXSourcesBuildPhase, PBXFrameworksBuildPhase and PBXResourcesBuildPhase')
         current_node = self.nodes[build_phase_hex]
         # no useful key, use its isa value
         cur_path_key = current_node['isa']
         self.__set_to_result(parent_hex, build_phase_hex, cur_path_key)
-        print 'uniquify PBXBuildFile'
+        self.vprint('uniquify PBXBuildFile')
         for build_file_hex in current_node['files']:
             self.__unique_build_file(build_phase_hex, build_file_hex)
 
@@ -370,10 +387,35 @@ def __unique_build_file(self, parent_hex, build_file_hex):
             self.__result.setdefault('to_be_removed', []).extend((build_file_hex, file_ref_hex))
 
 
-if __name__ == '__main__':
-    if len(sys_argv) != 2:
-        raise SystemExit('usage: xUnique.py path/to/Project.xcodeproj')
-    else:
-        xcode_proj_path = sys_argv[1].decode(sys_get_fs_encoding())
-        xunique = XUnique(xcode_proj_path)
+def main(sys_args):
+    usage = "usage: %prog [[-u|--unique]|[-s|--sort (24|32)]] path/to/Project.xcodeproj"
+    description = "By default, without any option, xUnique uniquify and sort the project file."
+    parser = OptionParser(usage=usage, description=description)
+    parser.add_option("-v", "--verbose",
+                      action="store_true", dest="verbose", default=False,
+                      help="output verbose messages. default is False.")
+    parser.add_option("-u", "--unique", action="store_true", dest="unique_bool", default=False,
+                      help="uniquify the project file. default is False.")
+    parser.add_option("-s", "--sort", action="store_true", dest="sort_bool", default=False,
+                      help="sort the project file. default is False.")
+    (options, args) = parser.parse_args(sys_args[1:])
+    if len(args) < 1:
+        parser.print_help()
+        raise SystemExit("xUnique requires at least one positional argument: relative/absolute path to xcodeproj.")
+    xcode_proj_path = args[0].decode(sys_get_fs_encoding())
+    xunique = XUnique(xcode_proj_path, options.verbose)
+    if not (options.unique_bool or options.sort_bool):
+        print("Uniquify and Sort")
         xunique.unique_pbxproj()
+        print("Uniquify and Sort done")
+    else:
+        if options.unique_bool:
+            print('Uniquify...')
+            xunique.unique_project()
+        if options.sort_bool:
+            print('Sort...')
+            xunique.sort_pbxproj()
+
+
+if __name__ == '__main__':
+    main(sys_argv)