Winix.Wargs
0.3.0
Prefix Reserved
dotnet tool install --global Winix.Wargs --version 0.3.0
dotnet new tool-manifest
dotnet tool install --local Winix.Wargs --version 0.3.0
#tool dotnet:?package=Winix.Wargs&version=0.3.0
nuke :add-package Winix.Wargs --version 0.3.0
wargs
Read items from stdin and execute a command for each one. Cross-platform xargs replacement with sane defaults.
Line-delimited by default, {} placeholder substitution, parallel execution, batching, dry-run, confirm, and structured output.
xargs replacement (and works on Linux/macOS too).
Install
Scoop (Windows)
scoop bucket add winix https://github.com/Yortw/winix
scoop install winix/wargs
Winget (Windows, stable releases)
winget install Winix.Wargs
.NET Tool (cross-platform)
dotnet tool install -g Winix.Wargs
Direct Download
Download native binaries from GitHub Releases.
Usage
<input> | wargs [options] [--] <command> [args...]
Items are read from stdin (one per line by default) and each item is passed to the command. If the command contains {}, each item replaces the placeholder; otherwise items are appended as trailing arguments.
Examples
# Simple foreach — ssh to each server
cat servers.txt | wargs ssh {} "uptime"
# Parallel — format 4 files at a time
find . -name "*.cs" | wargs -P4 dotnet format {}
# Batch — pass 10 URLs per curl invocation
cat urls.txt | wargs -n10 curl
# Dry run — see what would be executed
find . -name "*.log" | wargs --dry-run rm
# Confirm — prompt before each deletion
find . -name "*.bak" | wargs -p rm
# JSON summary to stderr
git ls-files "*.cs" | wargs --json dotnet format {}
# Null-delimited input (find -print0)
find . -name "*.tmp" -print0 | wargs -0 rm
# Default echo — no command means print items
seq 5 | wargs
# Verbose — print each command before running
cat hosts.txt | wargs -v ping -c1 {}
# Fail fast — stop on first error
cat servers.txt | wargs --fail-fast ssh {} "systemctl restart app"
# Keep order — parallel but output in input order
cat urls.txt | wargs -P4 -k curl -s {}
# NDJSON — streaming per-job results to stderr
cat servers.txt | wargs --ndjson ssh {} "uptime"
# Windows — dir /b gives bare filenames, one per line
dir /b *.log | wargs del {}
How It Works
- Read items from stdin (line-delimited, null-delimited, custom delimiter, or POSIX whitespace)
- Build command invocations by substituting
{}or appending items, with optional batching (-n) - Execute jobs sequentially or in parallel (
-P), with configurable output buffering - Report results as human text, JSON summary, or streaming NDJSON
Options
| Option | Description |
|---|---|
-P, --parallel N |
Max concurrent jobs (default 1, 0 = unlimited) |
-n, --batch N |
Items per invocation (default 1) |
-0, --null |
Null-delimited input (for find -print0) |
-d, --delimiter CHAR |
Custom single-character input delimiter |
--compat |
POSIX whitespace splitting with quote handling |
--fail-fast |
Stop spawning after first child failure |
-k, --keep-order |
Print output in input order (parallel only) |
--line-buffered |
Children inherit stdio directly (no buffering) |
-p, --confirm |
Prompt before each job |
--dry-run |
Print commands without executing |
-v, --verbose |
Print each command to stderr before running |
--json |
JSON summary to stderr on exit |
--ndjson |
Streaming NDJSON per job to stderr |
--no-shell-fallback |
Disable shell fallback for builtins |
--no-color |
Disable colored output |
--color |
Force colored output |
--version |
Show version |
-h, --help |
Show help |
Differences from xargs
| Behaviour | xargs | wargs |
|---|---|---|
| Default delimiter | Whitespace with quote parsing | Newline (\n) |
| No command | echo |
echo |
| Placeholder | -I{} required |
{} auto-detected |
| Parallel | -P N |
-P N (same) |
| Batch | -n N appends multiple args |
-n N (same) |
| Fail fast | Not built-in | --fail-fast |
| Confirm | -p |
-p (same) |
| Dry run | Not built-in | --dry-run |
| JSON output | Not built-in | --json / --ndjson |
| Keep order | Not built-in | -k / --keep-order |
| Verbose | -t |
-v / --verbose |
Exit Codes
| Code | Meaning |
|---|---|
| 0 | All jobs succeeded |
| 123 | One or more child processes failed (or could not be spawned). Per-job spawn failures surface in fault_message rather than as a separate exit code — wargs intentionally collapses spawn failures into 123 + per-job diagnostic. |
| 124 | Aborted due to --fail-fast |
| 125 | Usage error (bad arguments) |
| 126 | Internal/IO failure: stdin read failed, or unexpected exception escaped to safety net |
| 130 | Cancelled by signal (Ctrl+C / SIGINT) |
Restrictions
--confirm(-p) and--verbose(-v) cannot be combined with--jsonor--ndjson. Confirm prompts and verbose plaintext lines write to stderr — the same channel as structured envelopes — and would interleave plaintext among JSON output. Wargs rejects these combinations at parse time withusage_error(exit 125).--ndjsonand--line-bufferedcannot be combined. Line-buffered children inherit stdio directly, which conflicts with NDJSON's stderr line discipline.--keep-orderand--line-bufferedcannot be combined. Order preservation requires per-job buffering.
Shell Builtins
Commands like echo, del, type, and ver are shell builtins on Windows — they don't exist as standalone .exe files. By default, wargs automatically retries failed commands via the platform shell (cmd /c on Windows, sh -c on Unix), so builtins work transparently:
dir /b *.log | wargs echo {}
Use --no-shell-fallback to disable this and require all commands to be standalone executables.
Colour
- Automatic: colour when outputting to a terminal, plain when piped
--colorforces colour on (overridesNO_COLOR)--no-colorforces colour off- Respects the
NO_COLORenvironment variable (no-color.org)
Part of Winix
wargs is part of the Winix CLI toolkit.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
This package has no dependencies.
| Version | Downloads | Last Updated |
|---|---|---|
| 0.3.0 | 105 | 5/26/2026 |
| 0.3.0-rc2 | 96 | 5/10/2026 |
| 0.2.0 | 109 | 4/16/2026 |
| 0.2.0-test4 | 101 | 4/15/2026 |
| 0.1.0 | 108 | 4/2/2026 |
## [0.3.0] - 2026-05-10
### Changed
- `--ndjson` now streams lines as jobs complete rather than buffering until `Task.WhenAll`. Pipeline consumers (`wargs ... --ndjson | jq -c .`) see results as they happen instead of in one batch at the end.
- `--keep-order --ndjson` honours per-input ordering by holding back lines for parallel out-of-order completion. Pre-fix the streaming change had broken keep-order; now reconciled.
- `--describe` JSON schema now advertises every emitted field across every mode. Pre-fix several fields were emitted but undocumented, breaking the introspection contract for AI agents and automation.
### Fixed
- Every exit path now emits a complete JSON envelope when `--json` or `--ndjson` is set. Previously cancellation, broken-pipe-during-stdin, and several fault paths bypassed the envelope and produced bare stderr lines, corrupting downstream JSON consumers.
- Ctrl+C during stdin read no longer escapes the safety-net catches — `wargs` now exits 130 with a complete JSON envelope under `--json` / `--ndjson`.
- Output formatter now sanitises lone UTF-16 surrogates, preventing invalid-JSON output when child process stdout contains malformed multi-byte sequences.
- CRLF handling is now culture-aware to avoid splitting in unexpected places under non-en-US locales.
- Captured child output is bounded by an OOM cap with line-atomic merge; a runaway child no longer crashes wargs itself.
- `--confirm` invalid responses (anything other than `y`/`n`/Enter) are now rejected with a re-prompt rather than being silently treated as accept.
- `--dry-run` no longer emits subprocess output — pre-fix the `RunDryRun` path leaked stdout from a no-op invocation in some shells.
- File-descriptor exhaustion / OOM / stack-overflow conditions now surface the standard exit codes (125 / 126) per suite convention rather than escaping as unhandled exceptions.
- `--version` output no longer carries the `+gitsha` SourceLink suffix.
### Added
- Library seam `Winix.Wargs.Cli.Run` for orchestration testing without process spawning.
- Documentation: README, man page, and `--describe` text now explicitly cover exit code 130 (Ctrl+C), per-mode field schemas, and the restrictions section.
### Internal
- UTF-8 console adoption via `ConsoleEnv.UseUtf8Streams`.
- Standard `<PackageTags>` set on the NuGet package.
- Platform-skipped tests migrated to `SkippableFact + Skip.IfNot`.
See full changelog at https://github.com/Yortw/winix/blob/main/src/wargs/CHANGELOG.md