Golang: Find Replace Script
Here's a find replace script for all files in a dir.
Features:
- Do whole directory, including nested sub directories.
- Use a file extension or regex to filter files.
- If a list of file paths is give, only do those files.
- Can auto backup of changed files.
- Can have more than 1 find replace pairs.
- Assume file is utf8 encoding.
// find replace string pairs in a dir // no regex // version 2019-01-13 // website: http://xahlee.info/golang/goland_find_replace.html package main import ( "fmt" "io/ioutil" "os" "path/filepath" "regexp" "strings" "time" ) const ( // inDir is dir to start. must be full path inDir = "/Users/xah/web/ergoemacs_org/" fnameRegex = `\.html` writeToFile = true doBackup = true backupSuffix = "~~" ) var dirsToSkip = []string{".git"} // fileList if not empty, only these are processed. Each element is a full path var fileList = []string{ // sample lines "/Users/xah/web/ergoemacs_org/emacs/elisp_count-region.html", "/Users/xah/web/ergoemacs_org/emacs/elisp_run_current_file.html", "/Users/xah/web/ergoemacs_org/emacs/elisp_delete-current-file.html", } // frPairs is a slice of frPair struct. var frPairs = []frPair{ frPair{ fs: `find string here, can be multi lines`, rs: `replace string here, can be multi lines`, }, frPair{ fs: `find string 2`, rs: `replace string 2`, }, // add more pairs here } // ------------------------------------------------------------ type frPair struct { fs string // find string rs string // replace string } // stringMatchAny return true if x equals any of y func stringMatchAny(x string, y []string) bool { for _, v := range y { if x == v { return true } } return false } func doFile(path string) error { contentBytes, er := ioutil.ReadFile(path) if er != nil { panic(er) } var content = string(contentBytes) var changed = false for _, pair := range frPairs { var found = strings.Index(content, pair.fs) if found != -1 { content = strings.Replace(content, pair.fs, pair.rs, -1) changed = true } } if changed { fmt.Printf("〘%v〙\n", path) if writeToFile { if doBackup { err := os.Rename(path, path+backupSuffix) if err != nil { panic(err) } } err2 := ioutil.WriteFile(path, []byte(content), 0644) if err2 != nil { panic("write file problem") } } } return nil } var pWalker = func(pathX string, infoX os.FileInfo, errX error) error { if errX != nil { fmt.Printf("error 「%v」 at a path 「%q」\n", errX, pathX) return errX } if infoX.IsDir() { if stringMatchAny(filepath.Base(pathX), dirsToSkip) { return filepath.SkipDir } } else { var x, err = regexp.MatchString(fnameRegex, filepath.Base(pathX)) if err != nil { panic("stupid MatchString error 59767") } if x { doFile(pathX) } } return nil } func main() { scriptPath, errPath := os.Executable() if errPath != nil { panic(errPath) } fmt.Println("-*- coding: utf-8; mode: xah-find-output -*-") fmt.Printf("%v\n", time.Now()) fmt.Printf("Script: %v\n", filepath.Base(scriptPath)) fmt.Printf("In dir: %v\n", inDir) fmt.Printf("File regex filter: %v\n", fnameRegex) fmt.Printf("Write to file: %v\n", writeToFile) fmt.Printf("Do backup: %v\n", doBackup) fmt.Printf("fileList: %#v\n", fileList) fmt.Printf("Find replace pairs: 「%#v」\n", frPairs) fmt.Println() if len(fileList) >= 1 { for _, v := range fileList { doFile(v) } } else { err := filepath.Walk(inDir, pWalker) if err != nil { fmt.Printf("error walking the path %q: %v\n", inDir, err) } } fmt.Println() if !writeToFile { fmt.Printf("Note: writeToFile is %v\n", writeToFile) } fmt.Printf("%v\n", "Done.") }
Emacs Integration
This script is integrated with emacs.
If you use emacs:
- Install Emacs: xah-find.el, Find Replace in Pure Elisp
- bookmark the golang script so you can easily open it when you need find replace. [see Emacs: Bookmark]
- Open the golang script, change input dir and find replace strings.
- Alt+x
xah-run-current-file
to run the script. [see Emacs: Run Current File] - In output, Alt+x
xah-find-output-mode
, to highlight result, and press enter on highlighted find/replace string text or file path to open the file.
If you are using xah-fly-keys, many of the command above is already there. You still need to install xah-find.el for coloring the output.
[see Emacs: Xah Fly Keys]
Find Replace Scripts
If you have a question, put $5 at patreon and message me.