Real bash commands. Real PowerShell objects.
Install-Module PsBash
PowerShell ships aliases for ls, cat, sort, rm -- but they're lies. rm -rf fails. ls -la fails. sort -k3 -rn fails. They're Get-ChildItem, Get-Content, and Sort-Object wearing a disguise, rejecting every bash flag you throw at them.
PsBash makes the flags work -- and goes further. Every command returns typed .NET objects while producing bash-identical text output.
# Before: string parsing
PS> Get-Process | Format-Table -Auto | Out-String | ForEach-Object { $_ -split "`n" } |
>> Where-Object { $_ -match 'pwsh' }
# Good luck extracting CPU from that
# After: typed objects through the entire pipeline
PS> $top = ps aux | sort -k3 -rn | head 5
PS> $top[0].ProcessName # pwsh
PS> $top[0].CPU # 12.4 (decimal, not a string)
PS> $top[0].PID # 1847 (integer, not a substring)
PS> $top | Where-Object { $_.CPU -gt 5.0 } | ForEach-Object { Stop-Process $_.PID -WhatIf }PS> ls -la | grep '.ps1' | sort -k5 -h
-rw-r--r-- 1 beagle wheel 4521 Apr 2 00:57 PsBash.psd1
-rw-r--r-- 1 beagle wheel 89234 Apr 2 09:46 PsBash.Tests.ps1
-rw-r--r-- 1 beagle wheel 141234 Apr 2 09:46 PsBash.psm1
# grep matched the TEXT, but passed through the TYPED OBJECTS:
PS> $files = ls -la | grep '.ps1' | sort -k5 -h
PS> $files[0].GetType().Name # PSCustomObject (LsEntry)
PS> $files.Name # PsBash.psd1, PsBash.Tests.ps1, PsBash.psm1
PS> $files.SizeBytes | Measure-Object -Sum | Select -Expand Sum
234989PS> echo '{"db":"postgres","port":5432}' | jq '.db'
"postgres"
PS> cat app.log | grep ERROR | awk '{print $1, $3}' | sort | uniq -c | sort -rn | head 5
47 2024-01-15 DatabaseError
23 2024-01-15 TimeoutError
12 2024-01-15 AuthError
PS> find . -name '*.log' -mtime +7 | xargs rm -f # actually works on Windows| PsBash | Git Bash | Cygwin | WSL | Crescendo | |
|---|---|---|---|---|---|
| Install | Install-Module |
Git for Windows | 50+ packages | Hyper-V/WSL2 | Per-command XML |
| Footprint | 340 KB, 3 files | ~300 MB (MSYS2 runtime) | ~1-4 GB | ~1-15 GB (full distro) | Module + your wrappers |
rm -rf works |
Yes | Yes | Yes | Yes | If you configure it |
| Typed objects | Always | Never (strings) | Never (strings) | Never (strings) | If configured |
| Object pipeline | Types survive grep | sort | head |
Strings only | Strings only | Strings only | Varies |
| PowerShell integration | Native -- objects flow into cmdlets | Separate shell | Separate shell | Separate shell | Native |
| Cross-platform | Win/Lin/Mac | Windows only | Windows only | Windows only | Win/Lin/Mac |
| Commands | 68 built-in | ~80 (GNU coreutils) | ~200+ (full GNU) | All of Linux | Define your own |
| jq/awk/sed | Built-in, zero binaries | awk/sed yes, jq no | Yes (install pkg) | Yes (apt install) | Not included |
| PATH conflicts | None (AllScope aliases) | Shadows PowerShell | Shadows PowerShell | Filesystem boundary | None |
| Startup overhead | ~100 ms (module load) | New process per call | New process per call | ~1s (cold), ~200ms (warm) | ~100 ms |
# Install from PSGallery
Install-Module PsBash
# Or clone for development
git clone https://github.com/standardbeagle/ps-bash.git
Import-Module ./ps-bash/src/PsBash.psd168 bash commands work immediately:
ls -la # LsEntry objects
ps aux | sort -k3 -rn | head 5 # PsEntry objects, sorted by CPU
cat README.md | grep 'bash' | wc -l # WcResult with .Lines, .Words, .Bytes
find . -name '*.ps1' -type f # FindEntry objects
echo '{"a":1}' | jq '.a' # built-in JSON processor
du -sh * | sort -rh | head 10 # DuEntry objects, human-readable sizes
sed -i 's/foo/bar/g' config.txt # in-place file editing
tar -czf backup.tar.gz src/ # compression with .NET streams# Add to your PowerShell profile
Add-Content $PROFILE "`nImport-Module PsBash"Every PsBash command returns a PSCustomObject with a .BashText property. The terminal renders BashText (looks like real bash). Your code accesses typed properties.
ls -la
|
Invoke-BashLs
|
[LsEntry] objects
.Name = "README.md"
.SizeBytes = 4521 [int]
.Permissions = "-rw-r--r--" [string]
.Owner = "beagle" [string]
.LastModified = 2024-04-02... [DateTime]
.BashText = "-rw-r--r-- 1 beagle wheel 4521 Apr 2 ..."
Pipeline commands (grep, sort, head, tail, tee) match against BashText but pass through the original typed objects. This is the pipeline bridge -- the core architectural pattern.
| Category | Commands |
|---|---|
| Listing | ls find stat tree du pwd basename dirname |
| Files | cp mv rm mkdir rmdir touch ln |
| Content | cat head tail tac wc nl rev strings fold expand unexpand split |
| Search | grep rg |
| Text | sed awk cut tr uniq sort column join paste comm diff |
| Pipeline | tee xargs |
| Data | jq yq xan |
| System | ps env date hostname whoami which alias time sleep |
| Output | echo printf |
| Encoding | base64 md5sum sha1sum sha256sum file |
| Archive | gzip gunzip zcat tar |
| Math | seq expr |
Every command supports --help and tab completion for all flags.
| Task | PsBash | Native PowerShell |
|---|---|---|
| List files | ls -la |
Get-ChildItem -Force | Format-List |
| Find by name | find . -name '*.ps1' |
Get-ChildItem -Recurse -Filter *.ps1 |
| Top 5 CPU | ps aux | sort -k3 -rn | head 5 |
Get-Process | Sort-Object CPU -Desc | Select -First 5 |
| Count lines | wc -l file.txt |
(Get-Content file.txt).Count |
| Search files | grep -r 'TODO' src/ |
Select-String -Path src/* -Pattern TODO -Recurse |
| JSON field | cat f.json | jq '.name' |
(Get-Content f.json | ConvertFrom-Json).name |
| Delete tree | rm -rf dist/ |
Remove-Item dist/ -Recurse -Force |
| Disk usage | du -sh * | sort -rh |
Get-ChildItem | Sort Length -Desc | Select Name,Length |
Both sides give you objects. PsBash just lets you type what you already know.
Invoke-Pester ./tests/PsBash.Tests.ps1
# 795 tests: 795 passing, 1 skipped (Windows-specific)CI runs on Windows, Linux, and macOS via GitHub Actions.
| Feature | Linux/macOS | Windows |
|---|---|---|
| File permissions | Real POSIX (rwxr-xr-x) |
Approximated from ACLs |
ps backend |
/proc filesystem |
.NET System.Diagnostics.Process |
ln -s |
Works normally | Requires Developer Mode |
stat |
/usr/bin/stat |
Pure .NET implementation |
standardbeagle.github.io/ps-bash -- full command reference, object type specs, pipeline cookbook, cross-platform guide.
MIT
Issues and PRs welcome.