Winix.Wargs 0.3.0

Prefix Reserved
dotnet tool install --global Winix.Wargs --version 0.3.0
                    
This package contains a .NET tool you can call from the shell/command line.
dotnet new tool-manifest
                    
if you are setting up this repo
dotnet tool install --local Winix.Wargs --version 0.3.0
                    
This package contains a .NET tool you can call from the shell/command line.
#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

  1. Read items from stdin (line-delimited, null-delimited, custom delimiter, or POSIX whitespace)
  2. Build command invocations by substituting {} or appending items, with optional batching (-n)
  3. Execute jobs sequentially or in parallel (-P), with configurable output buffering
  4. 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 --json or --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 with usage_error (exit 125).
  • --ndjson and --line-buffered cannot be combined. Line-buffered children inherit stdio directly, which conflicts with NDJSON's stderr line discipline.
  • --keep-order and --line-buffered cannot 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
  • --color forces colour on (overrides NO_COLOR)
  • --no-color forces colour off
  • Respects the NO_COLOR environment variable (no-color.org)

Part of Winix

wargs is part of the Winix CLI toolkit.

Product 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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

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