Welcome, guest | Sign In | My Account | Store | Cart

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.

Python, 175 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

1 comment

cyril romain 17 years, 11 months ago  # | flag

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 !