Skip to content

Instantly share code, notes, and snippets.

@csmoore
Created April 3, 2015 16:06
Show Gist options
  • Save csmoore/15e46dedc5604c784b6d to your computer and use it in GitHub Desktop.
Save csmoore/15e46dedc5604c784b6d to your computer and use it in GitHub Desktop.
Simple find and replace string in files (recursive) python script
#------------------------------------------------------------------------------
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#------------------------------------------------------------------------------
# Filename: FindAndReplace.py
# Purpose: Simple find and replace string in files (recursive) script
# Usage: python FindAndReplace.py [Old String] [New String]
# [File Filters(ex/default:".txt,.html,.erb")] [Directory To Check]
# Requirement: Files must be text (non-binary) files
# (this is why we force you to pick the file pattern/filter)
# WARNING: This will overwrite files matching [File Filters]. All occurrences of [Old String]
# will be replaced with [New String]. Make sure you really, really want to do this.
#------------------------------------------------------------------------------
import os
import sys
import traceback
def usage():
print('Usage: python FindAndReplace.py [Old String] [New String] ' \
'[File Filters(default:".txt,.html,.erb")] [Directory To Check(.)]')
def replaceStringInFile(fileName, oldStringToReplace, newString):
if not(os.path.isfile(fileName) and os.access(fileName, os.W_OK)):
print("WARNING: Skipping...File does not exist or and is not writeable:" + fileName)
return False
fileUpdated = False
# credit/taken/adapted from: http://stackoverflow.com/a/4128194
# Read in old file
with open(fileName, 'r') as f:
newlines = []
for line in f.readlines():
if (oldStringToReplace in line) :
fileUpdated = True
line = line.replace(oldStringToReplace, newString)
newlines.append(line)
# Write changes to same file
if fileUpdated :
print("String Found and Updating File: " + fileName)
try:
with open(fileName, 'w') as f:
for line in newlines:
f.write(line)
except:
print('ERROR: Cannot open/access existing file for writing: ' + fileName)
return fileUpdated
def main():
try:
DEFAULT_PATH = '.'
if len(sys.argv) < 3:
usage()
# old/new string required parameters, exit if not supplied
sys.exit(-1)
else:
oldString = sys.argv[1]
newString = sys.argv[2]
if len(sys.argv) < 4:
patterns = ['.txt', '.html', '.erb']
else:
stringFilter = sys.argv[3]
patterns = stringFilter.split(',')
if len(sys.argv) < 5:
path = DEFAULT_PATH
else:
path = sys.argv[4]
print('[Old String] : ' + oldString)
print('[New String] : ' + newString)
print('[File Filters] : ' + ', '.join(patterns))
print('[Directory To Check] : ' + path)
if not os.path.exists(path):
raise Exception("Selected path does not exist: " + path)
# Walks through directory structure looking for files matching patterns
matchingFileList = \
[os.path.join(dp, f) \
for dp, dn, filenames in os.walk(path) \
for f in filenames \
if os.path.splitext(f)[1] in patterns]
print('Files found matching patterns: ' + str(len(matchingFileList)))
fileCount = 0
filesReplaced = 0
for currentFile in matchingFileList:
fileCount+=1
fileReplaced = replaceStringInFile(currentFile, oldString, newString)
if fileReplaced:
filesReplaced+=1
print("Total Files Searched : " + str(fileCount))
print("Total Files Replaced/Updated : " + str(filesReplaced))
except Exception as err:
print(traceback.format_exception_only(type(err), err)[0].rstrip())
sys.exit(-1)
if __name__ == '__main__':
main()
@csmoore
Copy link
Author

csmoore commented Oct 22, 2019

I don't - but if you have a link to the sample file, and the parameters used to run I can try to reproduce

@DaveHCL
Copy link

DaveHCL commented Oct 22, 2019

Hi Chris,
My apologies as I thought you might ask about that. And the file is proprietary for work.
I used the basic syntax of:
python FindAndReplace.py [Old String] [New String] *.xml .
I had to add encoding to the file open as this is an xml file. That allowed the file to be read, but something odd was going on with the read.
The file went from over 2 gigs to 200+KB
Sorry again,
Dave

@csmoore
Copy link
Author

csmoore commented Oct 22, 2019

Unfortunately this script probably needs some tweaks to work best with Unicode (Python 3) and with large files (currenlty copies file contents into memory) - sorry it didn't work

@DaveHCL
Copy link

DaveHCL commented Oct 22, 2019

No apology needed bud. I may have to tweak it and that is fine. And large files in Python have been a challenge for many many moons!
If you get some time, feel free to let me know so I can be a guinea pig for you :)
I love breaking er testing stuff!

@DaveHCL
Copy link

DaveHCL commented Oct 22, 2019

Quick question:
Do you see the value of trying to rework the line.replace with string.replace?

@csmoore
Copy link
Author

csmoore commented Oct 22, 2019

For a large file - I would probably restructure this script to read/write one line at a time.

@DaveHCL
Copy link

DaveHCL commented Oct 22, 2019

So I was able to get the script to work. I have to add encoding for the read and write phases. And I went from 1174 ocurances of the OldString down to 11. And those are embedded into some xml tags. For which I just did a find/replace in Notepad++ as I wanted to get this script to my teammate.
Thanks!!

@csmoore
Copy link
Author

csmoore commented Oct 23, 2019

Glad you were able to get something working - I guess Notepad++ is indeed another option if it is a non-batch case - but then you never get the fun of learning to work with unicode

@DaveHCL
Copy link

DaveHCL commented Oct 23, 2019

Ok so now you are being evil :) Putting a link to what seems to be a well crafted article on Unicode, gets me reading about it. And wanting to then use it. Almost like a real, grown up programmer. Which I am not by trade but am getting into more and more.
Thanks for the link. And for this script!

@Priya12233
Copy link

Hi
I tried to use your program to work with .xml file, and I am getting error. If possible plz check the below stackoverflow link for my query

https://stackoverflow.com/questions/67431852/why-the-python-file-handling-not-recognizing-file-name?noredirect=1#comment119189069_67431852

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment