$npx -y skills add flutter/agent-plugins --skill unix-cli-best-practicesSafe, portable, and efficient command-line patterns for macOS/BSD Unix tools (grep, find, sed, awk, xargs, mdfind, pbcopy, open) and modern alternatives (ripgrep, fd). Covers common shell scripting and one-liner use cases including fast searching, text processing, codebase naviga
| 1 | # Unix CLI best practices |
| 2 | |
| 3 | This guide provides efficient, safe, and portable techniques for manipulating text and finding files from the command line on macOS. By default, macOS uses BSD-derived UNIX utilities (`grep`, `find`, `sed`, `awk`) which have subtle differences from their GNU/Linux counterparts. |
| 4 | |
| 5 | When possible, use high-performance replacements (`ripgrep` and `fd`) which respect `.gitignore` rules by default and offer more ergonomic interfaces. |
| 6 | |
| 7 | ## Modern high-performance alternatives |
| 8 | |
| 9 | Use these tools instead of standard BSD utilities for local codebase operations. |
| 10 | |
| 11 | ### ripgrep (`rg`) |
| 12 | |
| 13 | Use `ripgrep` (`rg`) as the preferred tool for searching text. It is faster than standard `grep` and respects `.gitignore` rules by default. |
| 14 | |
| 15 | Common use cases: |
| 16 | * Run `rg 'search_term'` to recursively search the current directory. |
| 17 | * Run `rg -S 'term'` to search case-insensitively unless the query contains uppercase letters. Use `rg -i 'term'` for strict case-insensitivity. |
| 18 | * Run `rg -g '*.ts' -g '!*.spec.ts' 'term'` to search `.ts` files while excluding `.spec.ts` files. |
| 19 | * Run `rg -v 'ignore_me'` to print lines that do not match the pattern. |
| 20 | * Run `rg -l 'term'` to list only the names of matching files. Combine with `rg -0` for null-terminated output suitable for `xargs`. |
| 21 | * Run `rg -F 'foo()'` to treat the search pattern as a fixed string rather than a regular expression. |
| 22 | * Run `rg -w 'const'` to match whole words only. |
| 23 | * Run `rg -C 2 'term'` to show two lines of surrounding context. Use `rg -B 2` for preceding context or `rg -A 2` for succeeding context. |
| 24 | |
| 25 | Refer to `rg --help` for the complete options list. |
| 26 | |
| 27 | ### fd |
| 28 | |
| 29 | Use `fd` as the preferred tool for traversing the filesystem and finding files. It is faster than standard `find` and respects `.gitignore` rules by default. |
| 30 | |
| 31 | Common use cases: |
| 32 | * Run `fd 'pattern'` to find files matching the regex pattern anywhere in their path. |
| 33 | * Run `fd -e py -e txt` to filter results by file extensions. |
| 34 | * Run `fd -t d 'docs'` to find directories. Use `fd -t f` for files and `fd -t l` for symbolic links. |
| 35 | * Run `fd -H` to include hidden files, or `fd -I` to include ignored files (such as `node_modules`). Combine as `fd -HI` to search all files. |
| 36 | * Run `fd -p 'src/assets'` to match the pattern against the full path instead of just the filename. |
| 37 | * Run `fd -e log -x rm` to execute a command on each matching file individually. Use `-X` (e.g., `fd -e log -X rm`) to run the command once with all matching files as arguments. |
| 38 | * Run `fd -a 'pattern'` to return absolute paths instead of relative paths. |
| 39 | |
| 40 | Refer to `fd --help` for the complete options list. |
| 41 | |
| 42 | ## Built-in tools for macOS and BSD |
| 43 | |
| 44 | Use these built-in utilities only when `rg` and `fd` are unavailable. Apply precise filters to prevent performance degradation. |
| 45 | |
| 46 | ### Efficient searching with grep |
| 47 | |
| 48 | Do not use `grep | grep -v 'unwanted_dir'` to exclude directories. This approach reads all files before filtering them. Use native exclusion arguments instead to exclude directories at the filesystem level: |
| 49 | |
| 50 | ```bash |
| 51 | # Slow: reads binary and ignored files |
| 52 | grep -R "pattern" . | grep -v "node_modules" |
| 53 | |
| 54 | # Fast: skips the directory completely at the filesystem level |
| 55 | grep -R --exclude-dir=node_modules --exclude-dir=.git "pattern" . |
| 56 | ``` |
| 57 | |
| 58 | Common `grep` flags: |
| 59 | * `-r` or `-R` to search recursively. `-R` follows symbolic links, while `-r` does not. |
| 60 | * `-I` to ignore binary files for faster execution and clean output. |
| 61 | * `--exclude="*.min.js"` to ignore files matching a specific glob. |
| 62 | * `--include="*.dart"` to search only files matching a specific glob. |
| 63 | * `-l` to print only the names of files containing matches. |
| 64 | * `-Z` to print a null character after each filename, which is useful when piping to `xargs -0`. |
| 65 | |
| 66 | Example of safely deleting files containing a specific string: |
| 67 | ```bash |
| 68 | grep -rlZ -I --exclude-dir=node_modules "DEPRECATED_API" . | xargs -0 rm |
| 69 | ``` |
| 70 | |
| 71 | ### High-performance traversal with find |
| 72 | |
| 73 | Prevent `find` from traversing irrelevant directory trees by using the `-prune` option. |
| 74 | |
| 75 | ```bash |
| 76 | # Slow: traverses node_modules entirely, then filters output |
| 77 | find . -name "*.ts" | grep -v "node_modules" |
| 78 | |
| 79 | # Fast: skips node_modules entirely |
| 80 | find . -name "node_modules" -prune -o -name "*.ts" -print |
| 81 | ``` |
| 82 | |
| 83 | The expression `-name "node_modules" -prune` stops traversal when encountering a `node_modules` directory. The `-o` (OR) operator specifies that for any other directory or file ending in `.ts`, the path is printed. |
| 84 | |
| 85 | ### macOS portability with sed |
| 86 | |
| 87 | macOS uses BSD `sed`, which differs from GNU `sed` in its handling of in-place editing. |
| 88 | |
| 89 | Use the `-i` option with an explicit backup extension. To edit in-place without creating |