Golang : Find and replace data in all files recursively
Alright, this tutorial is an enhancement of previous tutorial on how to search for file recursively with wildcard support. In this tutorial, we will search for files that matches the search criteria and replace data inside
the files with replacement data. Kinda like refactoring.
Here you go!
package main
import (
"bytes"
"fmt"
"io"
"io/ioutil"
"math/rand"
"os"
"path/filepath"
"time"
)
var (
targetFolder string
targetFile string
searchData string
replaceData string
searchResult []string
)
func findFile(path string, fileInfo os.FileInfo, err error) error {
// recording in progress ticker. From good old DOS days.
ticker := []string{
"-",
"\\", //<--- need escape
"/",
"|",
}
rand.Seed(time.Now().UnixNano())
if err != nil {
fmt.Println(err)
return nil
}
// get absolute path of the folder that we are searching
absolute, err := filepath.Abs(path)
if err != nil {
fmt.Println(err)
return nil
}
if fileInfo.IsDir() {
//fmt.Println("Searching directory ... ", absolute)
fmt.Printf("\rSearching and replacing data in file(s) .... [%v]", ticker[rand.Intn(len(ticker)-1)])
// correct permission to scan folder?
testDir, err := os.Open(absolute)
if err != nil {
if os.IsPermission(err) {
fmt.Println("No permission to scan ... ", absolute)
fmt.Println(err)
}
}
testDir.Close()
return nil
} else {
// ok, we are dealing with a file
// is this the target file?
// yes, need to support wildcard search as well
// https://www.socketloop.com/tutorials/golang-match-strings-by-wildcard-patterns-with-filepath-match-function
matched, err := filepath.Match(targetFile, fileInfo.Name())
if err != nil {
fmt.Println(err)
}
if matched {
// yes, add into our search result
add := "Found : " + absolute
searchResult = append(searchResult, add)
add = "Creating backup copy of " + absolute
originalFile, err := os.Open(absolute)
if err != nil {
fmt.Println(err)
}
defer originalFile.Close()
searchResult = append(searchResult, add)
backup := absolute + ".bak"
backupFile, err := os.Create(backup)
if err != nil {
fmt.Println(err)
}
defer backupFile.Close()
// do the actual work
_, err = io.Copy(backupFile, originalFile)
if err != nil {
panic(err)
}
add = "Backing up to " + backup
searchResult = append(searchResult, add)
//covert *os.File to []byte
originalFileBytes, _ := ioutil.ReadFile(absolute)
// ok, now we want to replace the data inside the file
replaced := bytes.Replace(originalFileBytes, []byte(searchData), []byte(replaceData), -1)
if err = ioutil.WriteFile(absolute, replaced, 0666); err != nil {
panic(err)
}
add = "Successfully replaced the target data with replacement data"
searchResult = append(searchResult, add)
}
}
return nil
}
func main() {
if len(os.Args) != 5 {
fmt.Printf("USAGE : %s <target_directory> <target_file> <search> <replace> \n", os.Args[0])
os.Exit(0)
}
targetFolder = os.Args[1]
targetFile = os.Args[2]
searchData = os.Args[3]
replaceData = os.Args[4]
fmt.Println("Searching for [", targetFile, "]")
fmt.Println("Starting from directory [", targetFolder, "]")
fmt.Println("Replacing [", searchData, "] with [", replaceData, "]")
// sanity check
testFile, err := os.Open(targetFolder)
if err != nil {
fmt.Println(err)
os.Exit(-1)
}
defer testFile.Close()
testFileInfo, _ := testFile.Stat()
if !testFileInfo.IsDir() {
fmt.Println(targetFolder, " is not a directory!")
os.Exit(-1)
}
err = filepath.Walk(targetFolder, findFile)
if err != nil {
fmt.Println(err)
os.Exit(-1)
}
// display our search result
fmt.Println("\n@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@")
for _, v := range searchResult {
fmt.Println(v)
}
}
Sample usage:
Let's replace all the "FileSystem" words in ALL the file.go files found in ALL the sub-directories under /Users/sweetlogic
./main ../. file.go "FileSystem" "SystemFile"
Searching for [ file.go ]
Starting from directory [ ../. ]
Replacing [ FileSystem ] with [ SystemFile ]
Searching and replacing data in file(s) .... [-]
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
Found : /Users/sweetlogic/.go/src/golang.org/x/net/webdav/file.go
Creating backup copy of /Users/sweetlogic/.go/src/golang.org/x/net/webdav/file.go
Backing up to /Users/sweetlogic/.go/src/golang.org/x/net/webdav/file.go.bak
Successfully replaced the target data with replacement data
Inspecting the /Users/sweetlogic/.go/src/golang.org/x/net/webdav/file.go
file will show that the word FileSystem
replaced by SystemFile
.
Hope this helps and happy coding!
References:
https://www.socketloop.com/tutorials/golang-command-line-ticker-to-show-work-in-progress
https://socketloop.com/tutorials/golang-simple-file-scaning-and-remove-virus-example
https://socketloop.com/tutorials/golang-search-folders-for-file-recursively-with-wildcard-support
See also : Golang : Search folders for file recursively with wildcard support
By Adam Ng
IF you gain some knowledge or the information here solved your programming problem. Please consider donating to the less fortunate or some charities that you like. Apart from donation, planting trees, volunteering or reducing your carbon footprint will be great too.
Advertisement
Tutorials
+21.4k Golang : How to reverse slice or array elements order
+13.8k Golang : How to pass map to html template and access the map's elements
+30.9k Golang : Example for ECDSA(Elliptic Curve Digital Signature Algorithm) package functions
+12.4k Golang : Convert int(year) to time.Time type
+14.6k Golang : How to check if IP address is in range
+10.1k Golang : Generate 403 Forbidden to protect a page or prevent indexing by search engine
+9.6k Golang : Bcrypting password
+24.7k Golang : Convert long hexadecimal with strconv.ParseUint example
+16.2k Golang : File path independent of Operating System
+14.8k Golang : How to get Unix file descriptor for console and file
+7.2k Golang : Set horizontal, vertical scroll bars policies and disable interaction on Qt image
+11.3k Golang : GTK Input dialog box examples