This script search and replace files in a directory, recursively.
file name and search string can be a regular expression.
Execution can be simulated, step by step, and are always shown changed files/lines.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 | # regexplace: regular expression search and replace
# Stefano Spinucci
# 2006-02-07 (rev 4)
# thanks to roadrunner.py
# http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/52553
# for some ideas and some code
# tested with python 2.3.5
import sys, os, re, string
# pupulate and return 'fileslist[]' with all files inside 'dir' matching 'regx'
def make_files_list(dir, regx):
# if dir is not a directory, exit with error
if not os.path.isdir(dir):
sys.exit(dir + ' is not a valid dir to walk !!!')
# compile the search regexp
cregex=re.compile(regx)
# initialize the file list
fileslist = []
# loop on all files and select files matching 'regx'
for root, dirs, files in os.walk(dir):
for name in files:
if cregex.search(name):
path = os.path.join(root, name)
fileslist.append(path)
# return the file list
return fileslist[:]
# in all files in 'fileslist' search the regexp 'searchregx' and replace
# with 'replacestring'; real substitution in files only if 'simulation' = 0;
# real substitution may also be step by step (if 'stepbystep' = 1)
def replace_in_files(fileslist, searchregx, replacestring, simulation, stepbystep):
# compile regexp
cregex=re.compile(searchregx)
# print message to the user
if simulation == 1:
print '\nReplaced (simulation):\n'
else:
print '\nReplaced:\n'
# loop on all files
for xfile in fileslist:
# initialize the replace flag
replaceflag=0
# open file for read
readlines=open(xfile,'r').readlines()
# intialize the list counter
listindex = -1
# search and replace in current file printing to the user changed lines
for currentline in readlines:
# increment the list counter
listindex = listindex + 1
# if the regexp is found
if cregex.search(currentline):
# make the substitution
f=re.sub(searchregx,replacestring,currentline)
# print the current filename, the old string and the new string
print '\n' + xfile
print '- ' + currentline ,
if currentline[-1:]!='\n': print '\n' ,
print '+ ' + f ,
if f[-1:]!='\n': print '\n' ,
# if substitution is real
if simulation == 0:
# if substitution is step by step
if stepbystep == 1:
# ask user if the current line must be replaced
question = raw_input('write(Y), skip (n), quit (q) ? ')
question = string.lower(question)
# if quit
if question=='q':
sys.exit('\ninterrupted by the user !!!')
# if skip
elif question=='n':
pass
# if write
else:
# update the whole file variable ('readlines')
readlines[listindex] = f
replaceflag=1
# if substitution is not step by step
else:
# update the whole file variable ('readlines')
readlines[listindex] = f
replaceflag=1
# if some text was replaced
# overwrite the original file
if replaceflag==1:
# open the file for writting
write_file=open(xfile,'w')
# overwrite the file
for line in readlines:
write_file.write(line)
# close the file
write_file.close()
# main function
def main():
# if parameters are wrong, exit with error
if len(sys.argv) < 5:
print '\nUsage:'
print 'python regexplace.py dirname files-regexp search-regexp replace-string'
sys.exit(1)
# ask user for simulated execution or real substitution
print '\nyou are replacing %s with %s in %s' %(sys.argv[3], sys.argv[4], sys.argv[2])
question1 = raw_input('continue with real substitution (y/N) ? ')
question1 = string.lower(question1)
# if user selected real substitution, ask user if execution must be step by step
if question1=='y':
question2 = raw_input('\nsubstitute step by step (Y/n) ? ')
question2 = string.lower(question2)
# make the file list
fileslist = make_files_list(sys.argv[1], sys.argv[2])
# if real substitution
if question1=='y':
# if step by step
if question2!='n':
replace_in_files(fileslist, sys.argv[3], sys.argv[4], 0, 1)
# if not step by step
else:
replace_in_files(fileslist, sys.argv[3], sys.argv[4], 0, 0)
# if simulated execution
else:
replace_in_files(fileslist, sys.argv[3], sys.argv[4], 1, 0)
if __name__ == '__main__':
main()
|
revision 4: added step by step execution revision 3: added simulation revision 2: minor improvements
Tags: text
For a better user interaction. There are many python scripts in Gentoo Linux that just require to press a key to answer a question like (Y/n); really great to answer a lot of questions like you may have in the step-by-step mode of regexplace.py !
The solution is to use a getch() python function, for example the one provided by this script: http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/134892
Just save it getch.py, and add 'import getch' in regexplace.py. Then replace each question of type:
question = raw_input('write(Y), skip (n), quit (q) ? ')
question = string.lower(question)
by:
print 'write(Y), skip (n), quit (q) ? '
question = string.lower(getch.getch())
That's all !
Thanks Stefano for this powerful script !