Skip to main content

PowerShell to Bash Converter

Paste a PowerShell script and get a best-effort bash translation: Write-Host to echo, Get-ChildItem to ls, Select-String to grep, $env: to export, if conditions to [ ] tests, foreach to for loops, and more. Every line is flagged MAPPED or UNMAPPED — unmapped lines are emitted as comments so they can never run blindly. Need the other direction? Try the Bash to PowerShell Converter.

✓ 100% client-side — nothing you paste leaves your browser
⚠ Heuristic mapping, not a transpiler — always review the output

The mapping table

Every rule below is implemented in the converter above — nothing here is aspirational. Constructs with no honest equivalent are flagged UNMAPPED instead of being faked.

PowerShell construct → bash
PowerShellBashNotes
Write-Host "text"echo "text"-NoNewline → -n; backtick-n inside the string → echo -e.
Write-Output "text" / echoecho "text"Write-Error → echo ... >&2.
Get-ChildItem [path]ls [path]-Force → -a; -Recurse → find.
Get-ChildItem -Recurse -Filefind path -type f-Filter → -name; -Directory → -type d.
Get-Content fcat f-Tail n → tail -n n; -Wait → tail -f.
Set-Content -Path f -Value "v"echo "v" > fAdd-Content → >>; -NoNewline → printf.
... | Out-File f... > f-Append → >>.
Set-Location d / Get-Locationcd d / pwdStraight renames; Push-Location/Pop-Location → pushd/popd.
Copy-Item -Path s -Destination dcp s d-Recurse → -r; -Force → -f.
Move-Item s d / Rename-Itemmv s d 
Remove-Item pathrm path-Recurse → -r; -Force → -f.
New-Item -ItemType Directorymkdir -p d-ItemType File → touch f; SymbolicLink → ln -s.
Test-Path p[ -e p ]-PathType Leaf → -f; Container → -d.
$env:X = vexport X=vReading $env:X → $X.
$x = "v"x="v"$null → ""; $true/$false → true/false.
"text $x""text ${x}"Braced interpolation keeps the variable boundary safe.
$x = commandx="$(command)"Pipelines inside are converted too.
$arr = @("a", "b")arr=("a" "b") 
Read-Host "p"read -p "p" REPLY$x = Read-Host "p" → read -p "p" x; -AsSecureString → -s.
Start-Sleep -Seconds nsleep n-Milliseconds → fractional seconds.
Get-Datedate-UFormat passes strftime through; -Format (.NET) needs manual port.
Compare-Object (Get-Content a) (Get-Content b)diff a b 
Select-String -Pattern "p"grep "p"-NotMatch → -v; -Quiet → -q.
Get-ChildItem -Recurse | Select-Stringgrep -r "p" pathMerged into one recursive grep.
Select-Object -First/-Last nhead/tail -n n-Skip n → tail -n +N.
Sort-Objectsort-Descending → -r; -Unique → -u.
... | Get-Unique... | uniqSort first: uniq only collapses adjacent duplicates.
Measure-Object -Linewc -l-Word → -w; -Character → -m.
Invoke-WebRequest -Uri U -OutFile fcurl -o f U-Method/-Body supported; auth options need manual port.
Get-Command cwhich c 
Get-Process / Stop-Processps aux / kill-Name → pgrep/pkill.
Expand-Archive / Compress-Archiveunzip|tar / zip|tarChosen by file extension.
Clear-Hostclear 
if (cond) {if [ cond ]; then-eq → =; -match → [[ =~ ]]; -and/-or → &&/||.
elseif (cond) {elif [ cond ]; then 
foreach ($x in ...) {for x in ...; doArrays → "${arr[@]}"; ranges 1..5 → {1..5}.
for ($i=0; $i -lt 5; $i++) {for (( i=0; i -lt 5; i++ )); do 
while (cond) {while [ cond ]; do 
function name {name() { 
switch ($x) {case "$x" in ... esacArms become pattern) ... ;;.
throw "msg"echo "msg" >&2; exit 1 
Get-WmiObject / Get-CimInstance# [UNMAPPED]Windows-only; use /proc, sysfs, or distro tools.
HKLM:\... registry paths# [UNMAPPED]The Windows registry has no Linux equivalent.
[Type]::Method(...)# [UNMAPPED].NET interop has no bash equivalent.
try { } catch { }# [UNMAPPED]Port manually (consider set -e / trap).
Where-Object / ForEach-Object# [UNMAPPED]Rewrite as grep/sed/awk filters or while-read loops.
param(...) / class / enum# [UNMAPPED]PowerShell-only constructs; port manually.

Worked examples

Each pair below is produced by the converter itself — paste any input on the left into the tool above and you get the output on the right, including the honest UNMAPPED case.

PowerShell input → bash output
PowerShellBashRule
Write-Host "Hello, World!"echo "Hello, World!"Write-Host → echo
Get-ChildItem -Path /var/log -Forcels -a /var/log-Force → -a (hidden files)
$env:API_KEY = "secret123"export API_KEY="secret123"$env: → export
Write-Host "Hello, $name!"echo "Hello, ${name}!"interpolation → ${var}
if (Test-Path "config.yaml" -PathType Leaf) {if [ -f "config.yaml" ]; thenTest-Path → [ -f ]
foreach ($f in *.log) {for f in *.log; doforeach → for-in
Get-Content app.log | Select-Object -First 20cat app.log | head -n 20pipe segment mapping
Invoke-WebRequest -Uri https://example.com/tool.zip -OutFile tool.zipcurl -o tool.zip https://example.com/tool.zipdownload cmdlet → curl
$lines = Get-Content "app.log" | Measure-Object -Linelines="$(cat "app.log" | wc -l)"assignment → command substitution
Get-WmiObject Win32_Process# [UNMAPPED] Get-WmiObject Win32_Processhonest flag: Windows-only

Frequently asked questions

Is this a perfect PowerShell-to-bash transpiler?

No — it is a best-effort heuristic mapper, not a transpiler. It converts line by line using a defined rule table (Write-Host to echo, Get-ChildItem to ls, Select-String to grep, $env: to export, if conditions to [ ] tests, foreach to for loops, and so on). Every line is flagged MAPPED or UNMAPPED, and unmapped lines are emitted as comments so the script cannot run them blindly. Always review and test the output in a safe environment before running it.

What can this converter NOT convert?

Several PowerShell constructs have no bash equivalent and are flagged UNMAPPED: Get-WmiObject and Get-CimInstance (Windows-only), registry provider paths like HKLM:, .NET interop calls such as [System.IO.File]::ReadAllText(), try/catch/finally blocks, Where-Object and ForEach-Object script blocks, PowerShell classes and enums, param() blocks, here-strings, and Invoke-RestMethod (which parses JSON — use curl plus jq instead).

How are PowerShell variables converted to bash?

Simple variables keep their dollar sign: $name becomes $name. Inside double-quoted strings, "$name" becomes "${name}" so the name boundary is always safe. Environment variables map both ways: $env:PATH reads as $PATH, and $env:API_KEY = "x" becomes export API_KEY="x". Special values convert too: $null becomes "", $true/$false become true/false, $args becomes $@, and array literals @(1, 2) become bash arrays (1 2).

How are PowerShell if conditions converted?

Test-Path becomes the matching test: -PathType Leaf to [ -f ], Container to [ -d ], plain to [ -e ]. Comparison operators map as -eq to =, -ne to !=, while -gt, -lt, -ge and -le stay the same for numeric tests. Comparisons against $null become [ -z "$var" ], -match becomes [[ "$s" =~ pattern ]], -like becomes [[ "$s" == glob ]], and -and/-or become && and || between bracket tests.

How are PowerShell loops converted?

foreach ($f in *.log) becomes for f in *.log; do, foreach over an array becomes for x in "${arr[@]}"; do, and numeric ranges like 1..5 become brace expansion {1..5}. C-style for ($i = 0; $i -lt 5; $i++) becomes for (( i=0; i -lt 5; i++ )); do, while (...) becomes while [ ... ]; do, and switch ($x) becomes a case "$x" in ... esac block.

How are PowerShell pipes converted?

Each pipeline segment is converted independently and re-joined with the bash pipe: Select-String -Pattern becomes grep, Select-Object -First/-Last becomes head/tail -n, Sort-Object becomes sort, Measure-Object -Line becomes wc -l, and Get-Content becomes cat. A recursive Get-ChildItem piped into Select-String is merged into a single grep -r, and a trailing Out-File becomes a > or >> redirect.

Why are unmapped lines emitted as comments instead of being skipped?

Safety. A line like Get-WmiObject Win32_Process has no Linux equivalent, so emitting it as # [UNMAPPED] keeps the original text visible for your manual port while guaranteeing the generated script cannot execute something the converter did not understand. A skipped line would silently change what the script does.

Is my script sent to a server?

No. The conversion runs entirely in JavaScript inside your browser — no line of your script is transmitted anywhere. You can disconnect from the network after the page loads and the converter keeps working.

Can it convert bash back to PowerShell?

No. This tool is strictly one-way: PowerShell in, bash out. The reverse direction is a separate tool with its own mapping rules written specifically for bash syntax constructs.

Free tool by NRTechStudio