11#!/usr/bin/env python3
22
3- # Change the #! line occurring in Python scripts. The new interpreter
3+ # Change the #! line (shebang) occurring in Python scripts. The new interpreter
44# pathname must be given with a -i option.
55#
66# Command line arguments are files or directories to be processed.
1010# arguments).
1111# The original file is kept as a back-up (with a "~" attached to its name),
1212# -n flag can be used to disable this.
13- #
13+
14+ # Sometimes you may find shebangs with flags such as `#! /usr/bin/env python -si`.
15+ # Normally, pathfix overwrites the entire line, including the flags.
16+ # To change interpreter and keep flags from the original shebang line, use -k.
17+
18+
1419# Undoubtedly you can do this using find and sed or perl, but this is
1520# a nice example of Python code that recurses down a directory tree
1621# and uses regular expressions. Also note several subtleties like
3338new_interpreter = None
3439preserve_timestamps = False
3540create_backup = True
41+ keep_flags = False
3642
3743
3844def main ():
3945 global new_interpreter
4046 global preserve_timestamps
4147 global create_backup
42- usage = ('usage: %s -i /interpreter -p -n file-or-directory ...\n ' %
48+ global keep_flags
49+
50+ usage = ('usage: %s -i /interpreter -p -n -k file-or-directory ...\n ' %
4351 sys .argv [0 ])
4452 try :
45- opts , args = getopt .getopt (sys .argv [1 :], 'i:pn ' )
53+ opts , args = getopt .getopt (sys .argv [1 :], 'i:kpn ' )
4654 except getopt .error as msg :
4755 err (str (msg ) + '\n ' )
4856 err (usage )
@@ -54,6 +62,8 @@ def main():
5462 preserve_timestamps = True
5563 if o == '-n' :
5664 create_backup = False
65+ if o == '-k' :
66+ keep_flags = True
5767 if not new_interpreter or not new_interpreter .startswith (b'/' ) or \
5868 not args :
5969 err ('-i option or file-or-directory missing\n ' )
@@ -70,10 +80,14 @@ def main():
7080 if fix (arg ): bad = 1
7181 sys .exit (bad )
7282
83+
7384ispythonprog = re .compile (r'^[a-zA-Z0-9_]+\.py$' )
85+
86+
7487def ispython (name ):
7588 return bool (ispythonprog .match (name ))
7689
90+
7791def recursedown (dirname ):
7892 dbg ('recursedown(%r)\n ' % (dirname ,))
7993 bad = 0
@@ -96,6 +110,7 @@ def recursedown(dirname):
96110 if recursedown (fullname ): bad = 1
97111 return bad
98112
113+
99114def fix (filename ):
100115## dbg('fix(%r)\n' % (filename,))
101116 try :
@@ -164,12 +179,26 @@ def fix(filename):
164179 # Return success
165180 return 0
166181
182+
183+ def parse_shebang (shebangline ):
184+ shebangline = shebangline .rstrip (b'\n ' )
185+ start = shebangline .find (b' -' )
186+ if start == - 1 :
187+ return b''
188+ return shebangline [start :]
189+
190+
167191def fixline (line ):
168192 if not line .startswith (b'#!' ):
169193 return line
194+
170195 if b"python" not in line :
171196 return line
172- return b'#! ' + new_interpreter + b'\n '
197+ flags = b''
198+ if keep_flags :
199+ flags = parse_shebang (line )
200+ return b'#! ' + new_interpreter + flags + b'\n '
201+
173202
174203if __name__ == '__main__' :
175204 main ()
0 commit comments