xargs — Build and execute command lines from standard input across all 5 shells
Equivalents in every shell
Bashunix
find . -name '*.tmp' | xargs rmZshunix
find . -name '*.tmp' | xargs rmFishunix
find . -name '*.tmp' | xargs rmPowerShellwindows
Get-ChildItem -Recurse -Filter *.tmp | ForEach-Object { Remove-Item $_.FullName }Pipelines pass objects, so `ForEach-Object` (alias `%`) plays the xargs role.
Worked examples
Delete files found by `find` (safely, with NUL separator)
Bash
find . -name '*.tmp' -print0 | xargs -0 rmPowerShell
Get-ChildItem -Recurse -Filter *.tmp | Remove-Itemcmd.exe
for /f "delims=" %f in ('dir /s /b *.tmp') do del "%f"Run a command once per line of input
Bash
cat urls.txt | xargs -n1 curl -OPowerShell
Get-Content urls.txt | ForEach-Object { Invoke-WebRequest -Uri $_ -OutFile (Split-Path $_ -Leaf) }Run in parallel with 4 workers
Bash
cat urls.txt | xargs -n1 -P4 curl -OPowerShell
Get-Content urls.txt | ForEach-Object -Parallel { Invoke-WebRequest -Uri $_ -OutFile (Split-Path $_ -Leaf) } -ThrottleLimit 4Gotchas
- xargs splits on whitespace by default — filenames with spaces or newlines break it. Use `find -print0 | xargs -0` or `xargs -d '\n'`.
- PowerShell pipelines carry objects, not strings — call `.FullName`, `.Path`, etc. to get the bit you actually want.
- xargs `-I {}` inserts each item at a placeholder; PowerShell uses `$_` inside `ForEach-Object` for the same role.
- `ForEach-Object -Parallel` requires PowerShell 7+; Windows PowerShell 5.1 needs `Start-Job` or `Start-ThreadJob` for parallelism.
WSL & PowerShell Core notes
pwshpwsh has no `xargs` binary — `ForEach-Object` is the pipeline-loop equivalent. The big semantic difference: `xargs cmd a b c` batches inputs into ONE `cmd` invocation with many args (efficient for `rm`, `mv`); `ForEach-Object { cmd $_ }` runs `cmd` once per input (slower for high-cardinality cases). For batching in pwsh, use `Get-ChildItem ... | Remove-Item` (which natively accepts pipeline input) instead of constructing a per-item loop.
WSLWSL ships GNU xargs which supports `-d '\n'` (delimiter), `-P N` (parallel), and `-0` (NUL-separated). macOS ships BSD xargs which lacks `-d` — portable scripts targeting both should use `find ... -print0 | xargs -0` (NUL-separated, no flag dependency). Inside WSL on Windows-side files (`xargs -P 8 rm < /mnt/c/junk-list.txt`), DrvFs serializes some metadata operations, so `-P` may not give the speedup you expect.
Related glossary
Common tasks using xargs
- Escape a string for safe shell use
Quote / escape a string so it survives word-splitting, glob expansion, and interpretation as multiple arguments — the fix for "spaces in filename break my script" and shell-injection bugs.
- Run multiple commands in parallel
Execute several commands concurrently and wait for them all — useful for batch downloads, fan-out tasks, and CI test sharding.