170 lines
4.4 KiB
Markdown
170 lines
4.4 KiB
Markdown
# text-shark
|
|
|
|
A Go CLI for fast text search, in-place replacement, line deletion, and file deletion. Powered by [`rg`](https://github.com/BurntSushi/ripgrep) for content operations and [`fd`](https://github.com/sharkdp/fd) for file-name finding.
|
|
|
|
## Prerequisites
|
|
|
|
- [ripgrep](https://github.com/BurntSushi/ripgrep) (`rg`)
|
|
- [fd](https://github.com/sharkdp/fd) (`fd`)
|
|
- Go 1.21+ (to build from source)
|
|
|
|
**Install on Ubuntu/Debian:**
|
|
```sh
|
|
sudo apt install ripgrep fd-find
|
|
```
|
|
|
|
**Install on macOS:**
|
|
```sh
|
|
brew install ripgrep fd
|
|
```
|
|
|
|
## Installation
|
|
|
|
```sh
|
|
git clone https://github.com/jasonross/text-shark
|
|
cd text-shark
|
|
go build -o text-shark .
|
|
```
|
|
|
|
Move the binary somewhere on your `$PATH`:
|
|
```sh
|
|
mv text-shark /usr/local/bin/
|
|
```
|
|
|
|
## Commands
|
|
|
|
### `find`
|
|
|
|
Search for a pattern in file contents. Output is streamed directly from `rg`, preserving colors and formatting.
|
|
|
|
```sh
|
|
text-shark find <pattern> [path]
|
|
```
|
|
|
|
```sh
|
|
text-shark find 'TODO'
|
|
text-shark find 'TODO' ./src
|
|
text-shark find -i 'error' # case-insensitive
|
|
text-shark find -t go 'context' # Go files only
|
|
text-shark find -g '*.json' 'port' # glob filter
|
|
text-shark find -F 'foo.bar' # literal string (no regex)
|
|
```
|
|
|
|
| Flag | Description |
|
|
|------|-------------|
|
|
| `-i`, `--ignore-case` | Case-insensitive search |
|
|
| `-F`, `--fixed-strings` | Treat pattern as a literal string |
|
|
| `-t`, `--type` | File type filter (e.g. `go`, `py`, `js`) |
|
|
| `-g`, `--glob` | Glob pattern for file paths |
|
|
|
|
---
|
|
|
|
### `replace`
|
|
|
|
Replace all occurrences of a string (or regex) in matching files. Reports each modified file and the line numbers that changed.
|
|
|
|
```sh
|
|
text-shark replace <from> <to> [path]
|
|
```
|
|
|
|
```sh
|
|
text-shark replace 'foo' 'bar'
|
|
text-shark replace 'foo' 'bar' ./src
|
|
text-shark replace 'foo' 'bar' --dry-run # preview changes without writing
|
|
text-shark replace -r 'foo\d+' 'item' ./src # regex mode
|
|
text-shark replace -t go 'oldPkg' 'newPkg' # Go files only
|
|
```
|
|
|
|
**Example output:**
|
|
```
|
|
./internal/config.go: lines 12, 47
|
|
./cmd/root.go: lines 3
|
|
2 file(s) modified.
|
|
```
|
|
|
|
| Flag | Description |
|
|
|------|-------------|
|
|
| `--dry-run` | Print what would change without writing files |
|
|
| `-r`, `--regex` | Treat `<from>` as a regular expression |
|
|
| `-t`, `--type` | File type filter |
|
|
| `-g`, `--glob` | Glob pattern for file paths |
|
|
|
|
---
|
|
|
|
### `delete-line`
|
|
|
|
Delete all lines containing a pattern. Reports each modified file and the original line numbers that were removed.
|
|
|
|
```sh
|
|
text-shark delete-line <pattern> [path]
|
|
```
|
|
|
|
```sh
|
|
text-shark delete-line 'debug'
|
|
text-shark delete-line 'debug' ./src
|
|
text-shark delete-line 'debug' --dry-run
|
|
text-shark delete-line -r '^#.*TODO' ./src # regex mode
|
|
text-shark delete-line -t py 'print(' ./lib # Python files only
|
|
```
|
|
|
|
**Example output:**
|
|
```
|
|
./internal/server.go: deleted lines 5, 23
|
|
./cmd/run.go: deleted lines 1
|
|
2 file(s) modified, 3 line(s) deleted.
|
|
```
|
|
|
|
| Flag | Description |
|
|
|------|-------------|
|
|
| `--dry-run` | Print what would change without writing files |
|
|
| `-r`, `--regex` | Treat pattern as a regular expression |
|
|
| `-t`, `--type` | File type filter |
|
|
| `-g`, `--glob` | Glob pattern for file paths |
|
|
|
|
---
|
|
|
|
### `find-delete-files`
|
|
|
|
Find files by **name pattern** using `fd`, display the full candidate list, then prompt for a single group confirmation before deleting.
|
|
|
|
```sh
|
|
text-shark find-delete-files <pattern> [path]
|
|
```
|
|
|
|
```sh
|
|
text-shark find-delete-files '_backup'
|
|
text-shark find-delete-files '_backup' ./archive
|
|
text-shark find-delete-files '_backup' --yes # skip prompt (scripting)
|
|
text-shark find-delete-files '\.log$' -t f ./logs # files only, regex name
|
|
```
|
|
|
|
**Example output:**
|
|
```
|
|
Found 3 file(s):
|
|
./archive/data_backup.csv
|
|
./archive/config_backup.json
|
|
./logs/old_backup.log
|
|
|
|
Delete these 3 file(s)? [y/N] y
|
|
3 file(s) deleted.
|
|
```
|
|
|
|
| Flag | Description |
|
|
|------|-------------|
|
|
| `-y`, `--yes` | Skip confirmation prompt and delete all matches |
|
|
| `-t`, `--type` | fd type filter: `f` (file), `d` (dir), `l` (symlink) — defaults to `f` |
|
|
|
|
---
|
|
|
|
## Notes
|
|
|
|
- All `replace` and `delete-line` writes are **atomic**: changes are written to a temp file in the same directory, then renamed into place, so a failure mid-write cannot corrupt the original.
|
|
- `path` defaults to `.` (current directory) on all subcommands. All operations are recursive.
|
|
- `replace` and `delete-line` use `rg -l` internally to skip files that don't contain the pattern before doing any I/O.
|
|
|
|
## Running Tests
|
|
|
|
```sh
|
|
go test ./...
|
|
```
|