Software engineering

When to Use rg, nl, Vim, and apply_patch

How ripgrep, nl, Vim, and apply_patch divide repository search, numbered evidence, interactive editing, and reviewable automated changes.

Published Jul 20, 2026
ripgrepVimShellCodexDeveloper Tools
On this page
  1. Four tools, four responsibilities
  2. rg searches the repository
  3. rg compared with grep, git grep, find, and fd
  4. nl turns excerpts into stable evidence
  5. nl compared with cat -n, rg -n, and awk
  6. Vim is for an interactive editing session
  7. Vim compared with an IDE, sed, and patch editing
  8. apply_patch describes the intended change
  9. apply_patch compared with patch, git apply, and sed -i
  10. The tools form a sequence
  11. 1. Locate the relevant code
  12. 2. Read enough context
  13. 3. Apply the smallest coherent edit
  14. 4. Review and verify
  15. Common command pairings
  16. Selection rules
  17. References

Why would an automated coding workflow use rg, nl, and apply_patch instead of opening every file in Vim?

Because these tools solve different parts of the job. Searching a repository, producing stable line references, editing interactively, and applying a reviewable change are separate operations. Treating them as one operation makes automation harder to inspect and less reliable.

Four tools, four responsibilities

ToolPrimary jobInteractiveChanges filesBest fit
rgSearch text across filesNoNoLocate symbols, errors, configuration keys, and files containing a pattern
nlAdd line numbers to textNoNoProduce stable, readable excerpts with exact line references
VimBrowse and edit in a terminal sessionYesYesHuman-driven reading, navigation, and editing
apply_patchApply explicit file changes from a patchNoYesAutomated edits that should be narrow and reviewable

The distinction is more useful than asking which tool is best. rg cannot replace an editor. Vim can search and show line numbers, but it introduces an interactive session that an automated process does not need. apply_patch can change a file, but it is not a discovery tool.

rg searches the repository

rg is the executable name for ripgrep. It recursively searches files for a regular-expression pattern. Its default repository behavior is significant: it respects ignore files such as .gitignore and skips hidden and binary files unless the caller overrides those filters.[1]

Search the current repository:

rg "SecurityConfig"

Restrict the search to Java files:

rg "AccessDenied" -t java

Show only matching file names:

rg -l "AccessDenied"

Search ignored and hidden content only when that is intentional:

rg --hidden --no-ignore "legacySetting"

This default filtering is helpful for source code, but it can also hide the answer. Generated files, ignored local configuration, and hidden directories require explicit flags. rg -uuu disables all automatic filtering, so it should be used deliberately rather than as the normal starting point.

rg compared with grep, git grep, find, and fd

ToolWhat it searchesRepository-aware defaultWorks outside GitPrefer it when
rgFile contentsRespects ignore files and skips hidden or binary filesYesSearching source trees quickly with concise flags
grepFile contents or standard inputNoYesPortability matters or another command is producing the input stream
git grepContents of files known to GitUses the Git index and working treeNoThe search must stay within tracked repository content
findPaths and filesystem metadataNot applicableYesSelecting files by name, type, size, owner, or timestamp
fdPathsRespects ignore files by defaultYesFinding files with shorter syntax than find

The closest content-search alternatives are grep and git grep. find and fd answer a different question: which paths match? They are often paired with a content search, but they do not replace one.

nl turns excerpts into stable evidence

nl reads files or standard input and writes the text with line numbers added. GNU Coreutils documents separate numbering styles for body, header, and footer sections; -ba selects all body lines, including blank ones.[2]

Number every line:

nl -ba src/App.java

Read a focused range while preserving the original line numbers:

nl -ba src/App.java | sed -n '100,140p'

The second form is useful in code review and automated analysis. The result can be cited as src/App.java:117 without relying on terminal height, cursor position, or editor state.

nl does not search and does not modify the file. It prepares text for inspection. When only matching lines matter, rg -n is shorter:

rg -n "handleRequest" src/

Use nl when the surrounding block matters. Use rg -n when the matching locations are enough.

nl compared with cat -n, rg -n, and awk

ToolOutput scopeBlank-line behaviorSearch capabilityPrefer it when
nl -baEvery input lineNumbers blank linesNoA complete excerpt needs stable source line numbers
cat -nEvery input lineNumbers blank linesNoA quick full-file listing is enough
rg -nMatching linesOnly reports lines that matchYesMatch locations matter more than surrounding context
awk '{print NR, $0}'Every input lineNumbers blank linesCan filter with an expressionNumbering and field-aware transformation must happen together

cat -n is the shortest substitute for a simple listing. awk is more programmable, but that flexibility makes the intent less obvious when the only requirement is line numbering. nl -ba communicates that requirement directly.

Vim is for an interactive editing session

Vim combines navigation, search, editing, buffers, undo history, and commands inside a terminal interface. Its documentation is split between a task-oriented user manual and a detailed reference manual, both designed around an interactive editing session.[3]

A human can jump directly to a line:

vim +100 src/App.java

Inside Vim, /pattern, :set number, quickfix lists, and project plugins can cover much of the same ground as external tools. That is useful when one person owns the session and can interpret the screen.

An automated process has different constraints:

  • terminal dimensions affect what is visible;
  • modes and cursor state must be tracked;
  • key sequences depend on timing and configuration;
  • an interrupted session may leave swap files or partial edits;
  • the visible screen is harder to turn into structured evidence.

Vim remains a strong choice for human editing. It is simply the wrong interface for most unattended search-and-edit steps.

Vim compared with an IDE, sed, and patch editing

Tool or methodInteraction modelMulti-file navigationChange visibilityPrefer it when
VimFull-screen terminal sessionBuilt in, with buffers and quickfix supportReviewed after savingA person wants keyboard-driven exploration and editing
IDE or graphical editorFull-screen graphical sessionUsually built in with language toolingReviewed after savingRefactoring depends on language servers, debugging, or visual navigation
sed -iNon-interactive commandOperates on named filesThe command shows the transformation, not the resulting contextA predictable textual substitution is intentionally broad
Patch editingNon-interactive structured changeCan update several filesRemoved, added, and surrounding lines are explicitAutomation needs a narrow edit that can be reviewed before verification

Vim and an IDE optimize the human editing loop. sed -i and patch-based editing optimize repeatable execution. The distinction is interaction and reviewability, not editing power.

apply_patch describes the intended change

apply_patch is not a standard Linux utility. In Codex it is a patch-editing tool with explicit operations for adding, deleting, moving, and updating files. The current OpenAI implementation parses patch hunks and resolves their paths before applying file changes.[4]

A small update looks like this:

*** Begin Patch
*** Update File: src/config.ts
@@
-const timeout = 3000;
+const timeout = 5000;
*** End Patch

The old line provides context and the new line states the intended result. If the expected context no longer exists, the patch can fail instead of blindly changing an unrelated occurrence.

The format follows the same review principle as a unified diff: unchanged context identifies the location, while - and + identify removed and added lines.[5] Codex’s markers are its own patch grammar, so apply_patch should not be confused with the Unix patch utility or git apply.

After applying a change, Git remains the source of truth for review:

git diff -- src/config.ts

apply_patch performs the edit. It does not prove that the code builds, passes tests, or behaves correctly.

apply_patch compared with patch, git apply, and sed -i

ToolInput formatContext checkingCan check the Git indexPrefer it when
apply_patchCodex *** Begin Patch grammarYesNoCodex must add, update, move, or delete files with explicit context
patchConventional context or unified diffYesNoA standard patch must be applied outside a Git-specific workflow
git applyGit-compatible patchYesYes, with --indexA conventional diff should update a working tree without creating a commit
sed -iSubstitution expressionPattern-based rather than hunk-basedNoThe transformation is simple, mechanical, and safe across every match

apply_patch is closest to patch and git apply, but its envelope and file-operation markers are Codex-specific. sed -i is shorter for a uniform substitution; it is riskier when the same text appears in unrelated contexts.

The tools form a sequence

A typical codebase task has four distinct steps.

1. Locate the relevant code

rg -n "DEFAULT_TIMEOUT|requestTimeout" src/

2. Read enough context

nl -ba src/config.ts | sed -n '35,80p'

3. Apply the smallest coherent edit

Use apply_patch with the surrounding function or configuration block as context.

4. Review and verify

git diff --check
npm test

The commands are intentionally separate. Search output explains why a file was selected. The numbered excerpt establishes the current state. The patch records the change. The diff and tests verify different properties afterward.

Common command pairings

The tools remain useful together because path selection, content search, context reading, and editing are separate operations:

# Find files by path, then search their contents.
find src -name '*.java' -print
rg "AccessDenied" -t java src

# Search logs from another command.
kubectl logs deployment/api | rg "ERROR|WARN"

# Read a known code range with line numbers.
nl -ba src/App.java | sed -n '80,130p'

Selection rules

Use rg when the question is “where does this text occur?”

Use nl when the question is “what exactly is at these lines?”

Use Vim when a person wants an interactive editing environment.

Use apply_patch when an automated change should state its scope and preserve reviewable context.

None of these tools verifies the final behavior. After the edit, inspect the diff and run the narrowest relevant formatter, type checker, build, or test. That separation keeps discovery, modification, and verification independently visible.

References

[1] Andrew Gallant. “ripgrep README.”

[2] GNU Project. “nl: Number lines and write files.”

[3] Vim Project. “Vim User Manual: About the manuals.”

[4] OpenAI. “Codex apply-patch implementation.”

[5] GNU Project. “Detailed Description of Unified Format.”