A handy text-processing utility (sed/awk style): single binary, zero config, stdin/stdout friendly. Combines file search (find/list), batch rename, and classic Unix text filters (cut/trans/script) in one tool.
(This project code is generated by AI, then checked and corrected by human.)
-
list: List files and directories with filters (like
ls)- Recursive file/directory listing with glob, size, and time filters
- Sort by name/size/mtime/ctime/path with reverse option
- Multiple output formats: path (default), long (permissions + size + time + path), name
- File type filtering (regular files, directories, symlinks)
- Max recursion depth control
- Size filter expressions (
>1M,<=100K) - Time filter expressions (relative
<=1h,>7dand absolute>=2025-01-01)
-
find: Fast file content search (inspired by ripgrep)
- Single-process by default, multi-process via
-j N/-j 0(all cores) - Regular expression support
- Colored output with highlighting
- Line number display
- File filtering by glob pattern
- Binary file detection
.gitignoreaware by default, use--all/-Ato search ignored files-l/--files-with-matchesmode: print only file paths (likegrep -l)
- Single-process by default, multi-process via
-
replace: Fast file content search and replace (inspired by ripgrep)
- Single-process by default, multi-process via
-j N/-j 0(all cores) - Regular expression support
- Colored output with highlighting
- Line number display
- File filtering by glob pattern
- Binary file detection
- Dry-run mode for safe preview
- Intuitive argument parsing (2-argument smart mode)
.gitignoreaware by default, use--all/-Ato search ignored files
- Single-process by default, multi-process via
-
rename: Batch file renaming tool (inspired by f2)
- Regular expression matching
- Capture group replacement ($1, $2, etc.)
- Dry-run mode (preview before executing)
- Conflict detection
- Directory support
- Force mode for resolving conflicts
- Case-insensitive file system support
-
cut: Extract fields from delimited text (subset of POSIX
cut)-ffield mode only (no-c/-b)- Field lists:
N,N-M,N-(open-ended),-M(1..M), mixed1,3-5,7- - Custom delimiter (
-d, supports\t\n\\escapes) -sskips lines without the delimiter--output-delimiterfor rearranged output- Reads from file or stdin (no path /
-→ stdin)
-
trans: Apply text transformations per line
upper,lower,trim,squeeze(collapse whitespace runs),reverse(rune-wise)- Reads from file or stdin, writes to stdout
- Pipeline-friendly:
cat f | gx trans upper | gx trans trim
-
script: Run a Tengo script over input (sed/awk style)
- Line mode (default): injects
line/lineno/filename - File mode (
--whole): injectscontent/filename - Result convention via
__out(string → emit,false→ filter) - Safe default module whitelist;
--unsafeopens all - Per-execution timeout (
--timeout)
- Line mode (default): injects
gx/
├── cmd/
├── common/ # Shared utilities (size/time expressions, gitignore)
│ ├── find/ # File content search command (grep-like)
│ ├── list/ # List files and directories with filters (ls-like)
│ ├── replace/ # File content search and replace command
│ ├── rename/ # Batch file rename command
│ ├── cut/ # Field extraction (cut -f subset)
│ ├── trans/ # Per-line text transforms (upper/lower/...)
│ └── script/ # Tengo script runner (sed/awk style)
├── processor/ # Shared walk + worker-pool engine
├── stream/ # Unified stdin/file input
├── args/ # Shared argument parsing functionality
├── regex/ # Regular expression matching wrapper
├── walker/ # Concurrent file system traversal
├── README.md # English documentation
├── README_ZH.md # Chinese documentation
└── LICENSE # MIT License
-
args: Provides common argument parsing with support for:
- Simple 2-argument mode (pattern + path or pattern + replacement)
- Option handling with short and long forms
- Automatic help generation
-
regex: Wraps Go's regexp package with:
- Case-insensitive matching
- Fixed string support
- Capture group replacement
-
walker: Concurrent file system traversal with:
- Directory skipping (.git, node_modules, etc.)
.gitignoreaware traversal (lazy loading, multi-level inheritance)- Glob pattern filtering
- Binary file detection
- Max depth control
-
common: Shared utilities:
sizeexpr: Size filter expression parser (>1M,<=100K)timeexpr: Time filter expression parser (relative<=1h, absolute>=2025-01-01)gitignore: .gitignore rule parser and matcher
-
processor: Shared file-processing engine:
- Worker-pool pipeline over walker output
FileProcessorinterface (ProcessFile + HandleResult) reused by find/replace
-
stream: Unified stdin/file input:
IsStdin/OpenInput/ReadAll- Virtual filename
<stdin>for match reporting (used by later commands)
go install github.com/azhai/gx@latestOr build from source:
git clone https://github.com/azhai/gx.git
cd gx
make buildgx - A handy text-processing utility (sed/awk style)
Usage: gx <command> [OPTIONS] [ARGS...]
Commands:
find Search for patterns in files (like grep)
list List files and directories with filters (like ls)
replace Search and replace text in files
rename Batch rename files
cut Extract fields from delimited text (like cut -f)
trans Apply text transformations (upper/lower/trim/...)
script Run a Tengo script over input (sed/awk style)
Global Flags:
-h, --help Show help
-V, --version Show version
Use "gx <command> --help" for command-specific options.
| Code | Meaning |
|---|---|
| 0 | Success, matches/changes found |
| 1 | Success, but no matches / no files renamed |
| 2 | Error (bad args, IO failure, etc.) |
Exit codes follow the grep convention, so gx composes naturally in
shell pipelines and conditionals:
if gx find "TODO" src/; then
echo "has TODOs"
figx --version # print version + commit
gx -V # short formThe version is injected at build time from git (see make one /
make build), so a binary reports the exact tag and commit it was
built from.
# Basic search
gx find "pattern" # Search in current directory
gx find "pattern" /path/to/dir # Search in specific directory
# Search options
gx find -A "pattern" # Search all files (ignore .gitignore)
gx find -F "pattern" # Treat pattern as literal string
gx find -g "*.go" "func" # Search only in Go files
gx find -i "pattern" # Case insensitive search
gx find -j 4 "pattern" # Use 4 worker threads (default 1, -j 0 = all cores)
gx find -l "pattern" # Print only file paths with matches (like grep -l)
gx find -n "pattern" # Show line numbers (default)
gx find -N "pattern" # Hide line numbers
gx find --no-color "pattern" # Disable colored output
# Examples
gx find "TODO" src/ # Search for TODO in src/
gx find -i "error" -g "*.go" # Case insensitive search in Go files
gx find "TODO" src/ test/ # Search in multiple directories
gx find --all "debug" ./project # Search files ignored by .gitignore
gx find -l -i "error" -g "*.go" ./src # List Go files containing "error" (case-insensitive)
gx find -j 0 "pattern" ./large-project # Multi-threaded search using all cores
gx find -l "deprecated" -g "*.py" | xargs sed -i 's/deprecated/legacy/g' # Pipeline# Basic search and replace
gx replace "pattern" "replace" # Preview replace (dry-run)
gx replace "pattern" "replace" -x # Execute replacement
# Using explicit options
gx replace -f "pattern" -r "replace" # Explicit find and replace
gx replace -f "TODO" -r "FIXME" -x # Execute replacement
# Replace options
gx replace -A "pattern" "replace" # Search all files (ignore .gitignore)
gx replace -F "pattern" "replace" # Treat pattern as literal string
gx replace -g "*.go" "func" "FUNC" # Replace only in Go files
gx replace -i "pattern" "replace" # Case insensitive search
gx replace -j 4 "pattern" "replace" # Use 4 worker threads (default 1, -j 0 = all cores)
gx replace -n "pattern" "replace" # Show line numbers (default)
gx replace -N "pattern" "replace" # Hide line numbers
gx replace --no-color "pattern" "replace" # Disable colored output
gx replace -x # Execute replacement (default: dry-run)
# Examples
gx replace "TODO" "FIXME" # Preview: replace TODO with FIXME
gx replace "foo" "bar" -x # Execute: replace all 'foo' with 'bar'
gx replace -F "[test]" "demo" -x # Replace literal string '[test]'
gx replace -i "error" "warning" -g "*.go" -x # Case insensitive in Go files
gx replace --all "old" "new" ./project # Replace in files ignored by .gitignore
gx replace "TODO" "FIXME" src/ test/ # Replace in multiple directories
gx find -l "deprecated" -g "*.go" | xargs -I{} gx replace "deprecated" "legacy" -x "{}" # Pipeline# Basic usage
gx rename "foo" "bar" # Preview: replace 'foo' with 'bar' (dry-run)
gx rename "foo" "bar" /path/to/dir # With specific directory
# Using explicit options
gx rename -f "pattern" -r "replace" # Explicit find and replace
gx rename -f "foo" -r "bar" -x # Execute rename
# Options
gx rename -d # Include directories
gx rename -F "pattern" "replace" # Treat pattern as literal string
gx rename -g "*.jpg" "pattern" "replace" # Filter by file pattern
gx rename -i "pattern" "replace" # Case insensitive matching
gx rename -x # Execute (default: dry-run)
gx rename --force # Force rename even with conflicts
# Examples
gx rename "foo" "bar" # Preview: replace 'foo' with 'bar'
gx rename "foo" "bar" -x # Execute: replace 'foo' with 'bar'
gx rename "\.txt$" ".md" -x # Change .txt to .md extension
gx rename "(\d+)" "prefix_$1" -x # Add prefix to numbers
gx rename -i "IMG" "img" -g "*.jpg" # Case conversion for jpg files
gx rename "^" "2024_" -x # Add date prefix to all files
gx rename -F "[test]" "demo" -x # Replace literal string '[test]'list provides ls-like recursive file/directory listing with powerful
filtering, sorting, and formatting options.
# Basic listing
gx list # List all files in current directory (recursive)
gx list /path/to/dir # List files in specific directory
# Filter options
gx list -g "*.go" # Filter by glob pattern
gx list -t f # Type: f=file, d=directory, l=symlink, a=all (default)
gx list -S ">1M" # Size filter: >1M, <=100K, 1024, etc.
gx list -M "<=1h" # Mtime filter: relative (<=1h, >7d) or absolute (>=2025-01-01)
gx list --ctime "<=1d" # Ctime filter: same syntax as mtime
# Sort and format
gx list -s name # Sort by: name, size, mtime, ctime, path
gx list -s size -r # Reverse sort order
gx list --format long # Long format: permissions, size, mtime, path
gx list --format name # Name only format
gx list -L 2 # Max recursion depth (0 = unlimited)
# Examples
gx list ./src # Recursively list all files in src/
gx list -g "*.go" --size ">1K" --mtime "<=1d" ./src # Go files >1K modified today
gx list --format long --sort size --reverse ./data # Long format sorted by size descending
gx list --type d --max-depth 2 ./project # List directories up to depth 2
gx list -g "*.log" -S ">100M" /var/log # Find log files larger than 100MB
gx list -M "<=1h" -t f ./src # Files modified in the last hourcut is a subset of POSIX cut: it supports -f (field mode) only.
Reads from a file or stdin (no path / - → stdin), writes to stdout.
# Field selection
echo "a,b,c" | gx cut -f 2 -d , # → b
echo "a,b,c,d" | gx cut -f 2-3 -d , # → b,c
echo "a,b,c,d,e" | gx cut -f 2- -d , # → b,c,d,e (open-ended)
echo "a,b,c,d" | gx cut -f -2 -d , # → a,b (1..2)
echo "a,b,c,d,e" | gx cut -f 1,3-4 -d , # → a,c,d (mixed)
# Tab-delimited (default delimiter)
printf "x\ty\tz\n" | gx cut -f 2 # → y
# Skip lines without the delimiter
printf "a,b\nno-delim\nc,d\n" | gx cut -f 1 -d , -s # → a\nc
# Custom output delimiter
echo "a,b,c" | gx cut -f 1,3 -d , --output-delimiter=: # → a:c
# From a file
gx cut -f 1 -d , data.csvField spec syntax (1-based, like POSIX cut):
Nsingle fieldN-Minclusive rangeN-open-ended (N to end of line)-M1 to M- mixed comma-separated, e.g.
1,3-5,7-
Escapes supported in -d / --output-delimiter: \t \n \\.
trans applies one of the built-in transforms to each line of input.
Reads from a file or stdin (no path / - → stdin), writes to stdout.
echo "hello" | gx trans upper # → HELLO
echo " Hi " | gx trans trim # → Hi
echo " a b c " | gx trans squeeze # → a b c
echo "abc" | gx trans reverse # → cba
# From a file
gx trans lower names.txt
# Pipeline (chained transforms)
cat file | gx trans trim | gx trans lowerAvailable transforms:
| Transform | Effect |
|---|---|
upper |
Uppercase all letters |
lower |
Lowercase all letters |
trim |
Strip leading/trailing whitespace |
squeeze |
Collapse runs of whitespace to a single space, trim |
reverse |
Reverse the string rune-wise (Unicode-safe) |
script runs a Tengo script over the input
text — a lightweight alternative to sed/awk for ad-hoc transforms. The
script compiles once and executes per line (default) or per file (--whole).
The result goes into the __out variable; gx decides what to do based on
its type (string → emit, false/undefined → filter, other → fmt.Sprint).
Modes:
- Line mode (default): injects
line(string),lineno(int, 1-based),filename(string,<stdin>for stdin). - File mode (
--whole): injectscontent(whole file string),filename(string).
# -e: inline expression; safe modules (text/json/...) are pre-imported.
echo "hi" | gx script -e 'text.to_upper(line)' # → HI
# Filter: drop even lines
seq 4 | gx script -e 'lineno % 2 == 1 ? line : false'
# Line number prefix using fmt.sprintf
seq 3 | gx script -e 'fmt.sprintf("%d: %s", lineno, line)'
# Whole-file mode: count newlines
printf 'a\nb\nc\n' | gx script --whole -e 'text.count(content, "\n")' # → 3
# -f: load a full script (you control __out yourself)
gx script --whole -f agg.tengo *.logSecurity model — by default only pure-computation Tengo modules are
available: fmt, text (strings/strconv/regexp), json, math,
times, base64, hex, enum. --unsafe opens all modules
(os/exec/file/...) — only use with trusted input.
-e automatically pre-imports every safe module so expressions like
text.to_upper(line) work without an explicit import line. -f scripts
must import modules themselves.
Other flags: --timeout D (per-execution timeout, default 1s).
Full module/API reference: docs/script-api.md.
git clone https://github.com/azhai/gx.git
cd gx
make one # Build native binary (bin/gx)
make build # Cross-compile all platforms
make release # Cross-compile + SHA256SUMSCross-compile outputs are versioned with the git tag and short commit:
bin/gx-<version>-<os>-<arch> # e.g. bin/gx-v0.2.0-darwin-arm64
Supported targets: darwin-arm64, darwin-amd64, linux-arm64,
linux-amd64, windows-amd64.
The version and commit are injected via -ldflags, so ./bin/gx --version
reports the exact tag and commit it was built from.
Other Makefile targets:
make clean # Remove old binaries
make upx # Build and compress with upx
make upxx # Build and compress with upx --ultra-brutego test ./... -vMIT License - see LICENSE file for details.