Categorygithub.com/cespare/sub
repositorypackage
0.3.0
Repository: https://github.com/cespare/sub.git
Documentation: pkg.go.dev

# README

sub

Sub is a simple tool for doing find/replace across files.

Sub is a tool that modifies your files. Use it at your own risk. (In particular, commit or back up changes before you have sub go to town on your data.)

Sub (probably) doesn't work on Windows.

Installation

You'll need Go installed. Then:

$ go get github.com/cespare/sub

Usage

sub -h for help. This prints out:

Usage:
  sub [OPTIONS] <FIND> <REPLACE> <FILE1> <FILE2> ...
where OPTIONS are
  -d, --dry-run=false: Print out what would be changed without changing any files.
  -v, --verbose=false: Print out detailed information about each match.
If no files are listed, sub reads filenames from standard input, one name per line.

I usually use -dv the first time so that I see what sub is going to do without having it make any changes.

Sub matches the pattern against the file line-by-line, ignoring line termination markers (\r\n or \n). This means:

  • Multi-line regular expressions will never match multiple lines
  • Zero-width matching characters such as ^, $, or \A match once on each line

Examples

In order to give sub a list of files, I generally make use of my shell's globbing capabilities. For instance, I often use *.go to indicate all .go files in the current directory. I also make use of ZSH's recursive globbing; so **/*.go to indicate all .go files in all subdirectories. If you're a bash user, you can get the same feature via globstar (see man bash).

# Replace instances of 'foo' with 'bar' in all .txt files.
sub foo bar *.txt

# Replace instances of Foobar, case insensitive, with xxx in all .c files.
sub '(?i)(Foobar)' xxx *.c

# Surround all numbers in parentheses in all .txt files, recursively.
sub '\d+' '($0)' **/*.txt

# Replace sell -> buy, seller -> buyer, selling -> buying, etc.
sub 'sell(\S*)' 'buy$1' *.txt

If you don't give any filenames to sub, it will read names from stdin. This means that you can use another tool, like find(1), to prepare the list of files.

# Replace instances of 'foo' with 'bar' in .c files, recursively.
find . -name '*.c' | sub foo bar

Screenshot

screenshot

Notes

See the documentation for the regular expression syntax used by the FIND pattern here:

http://golang.org/pkg/regexp/syntax/

See documentation for the expansion syntax used in the REPLACE pattern here:

http://golang.org/pkg/regexp/#Regexp.Expand