Skip to content

Shell Translator

The same task in CMD, PowerShell and Linux bash side by side, with the gotchas: dir /s, deltree, findstr, ifconfig and 120 more.

For people who still type dir /s. Look up a task, not a command: "delete a folder and everything in it" shows rmdir /s /q, Remove-Item -Recurse -Force and rm -rf side by side, with the catch that bites when you switch between them. Search for anything you remember, including old names like deltree, xcopy or ifconfig, and pick which shell you're coming from. It's all built into the page: searching sends nothing anywhere.

Search tasks and commands

I know

Show

PowerShell's dir, ls and cat aren't the DOS or Linux commands
In PowerShell they're aliases for Get-ChildItem and Get-Content, so they take PowerShell parameters: dir -Recurse works, dir /s doesn't, and ls -la fails. On Linux and macOS, PowerShell 7 drops the aliases that clash with native tools, so ls there is the real ls.
PowerShell pipes objects; CMD and bash pipe text
Get-ChildItem | Where-Object Length -gt 1MB filters on a real number. In CMD and bash every command receives lines of text, which is why Linux leans on grep, awk and cut to pick text apart. Text tools in a PowerShell pipeline see the formatted output, not the objects.
Linux is case-sensitive; Windows isn't
Report.txt and report.txt are two different files on Linux, and commands, options and variables are case-sensitive too (-r and -R often mean different things). Windows file names and PowerShell cmdlets and parameters ignore case.
find is three different things
In CMD, find searches for text inside files. On Linux, find searches for files by name, size or date. PowerShell has no find alias, so typing find on Windows runs the CMD text-search tool find.exe.
> writes different encodings
Windows PowerShell 5.1 writes UTF-16 LE ("Unicode") with >, which many Linux tools and older programs can't read. PowerShell 7 writes UTF-8 without a BOM. CMD writes in the console code page. Use Out-File -Encoding utf8 or Set-Content when it matters.
Paths: backslash vs slash, drive letters vs one tree
Windows uses C:\Users\ann with a drive letter per volume; Linux has one tree from / with drives mounted inside it (/mnt/data). PowerShell accepts both / and \ on Windows; bash treats \ as an escape character, not a separator.
There's no Recycle Bin on the command line
del, Remove-Item and rm delete immediately on every platform; nothing goes to the Recycle Bin or Trash. rm -rf and Remove-Item -Recurse -Force don't ask first.
Quoting rules differ
CMD only understands double quotes and escapes with ^. PowerShell and bash both treat single quotes as literal and expand variables in double quotes, but PowerShell escapes with a backtick (`) and bash with a backslash.

127 tasks

Listing, copying, moving, renaming, deleting and linking files and folders.

TaskCMDPowerShellLinux (bash)
List files in a folder
dir
ls
Get-ChildItem
Aliases: gci, dir, ls
ls -l
Gotcha: PowerShell's dir and ls are Get-ChildItem, so dir /w and ls -la fail there. Linux ls hides dot files unless you add -a.
PowerShell 7 on Linux and macOS has no ls alias: ls runs the native ls.
List everything in a folder and its subfolders
dir /s
gci -r
Get-ChildItem -Recurse
Aliases: gci, dir, ls
ls -R
find . lists one path per line, easier to process.
Gotcha: dir /s prints a block per folder with totals; Get-ChildItem -Recurse emits file objects you can filter and sort; ls -R groups by folder like dir /s.
List full paths only, one per line
dir /s /b
gci -r -Name
Get-ChildItem -Recurse | ForEach-Object FullName
find .
Gotcha: -Name gives paths relative to the folder; use FullName for absolute paths. find prints paths starting with ./ unless you give it an absolute start folder.
List directories only
dir /a:d
gci -Directory
Get-ChildItem -Directory
ls -d */
Or: find . -maxdepth 1 -type d
Gotcha: dir /a:d also lists the . and .. entries. ls -d */ skips hidden folders unless dot globbing is on.
List files only (no folders)
dir /a:-d
gci -File
Get-ChildItem -File
find . -maxdepth 1 -type f
Gotcha: The minus in /a:-d means "not". ls has no files-only switch; find -type f is the usual answer.
Show hidden and system files
dir /a
gci -Force
Get-ChildItem -Force
-Hidden shows only hidden items.
ls -a
Gotcha: On Windows "hidden" is a file attribute; on Linux a file is hidden just because its name starts with a dot.
List newest files first (or by size)
dir /o:-d
/o:-s for largest first
gci | sort LastWriteTime -Desc
Get-ChildItem | Sort-Object LastWriteTime -Descending
ls -lt
ls -lS for largest first
Gotcha: dir /o:d is oldest first and the minus reverses it; ls -t is already newest first (add -r to reverse).
Find files by name anywhere under a folder
dir /s /b *.log
gci -r -Filter *.log
Get-ChildItem -Recurse -Filter *.log
find . -name '*.log'
Gotcha: Quote the pattern in bash, or the shell expands *.log in the current folder before find sees it. find -name is case-sensitive; use -iname to ignore case.
Copy a file
copy a.txt b.txt
cp a.txt b.txt
Copy-Item a.txt b.txt
Aliases: copy, cp, cpi
cp a.txt b.txt
Gotcha: CMD's copy asks before overwriting when you type it (not in batch files); Copy-Item and cp overwrite silently. Use cp -i to be asked.
Copy a folder and everything in it
robocopy src dst /e
xcopy src dst /e /i also works; robocopy is its more capable successor.
Copy-Item src dst -Recurse
Aliases: copy, cp, cpi
cp -r src dst
Gotcha: If dst already exists, Copy-Item -Recurse and cp -r put the copy inside it (dst\src); robocopy copies src's contents into dst. Check with the Robocopy builder for anything bigger than a quick copy.
Move a file or folder
move a.txt D:\Archive\
mv a.txt D:\Archive\
Move-Item a.txt D:\Archive\
Aliases: move, mv, mi
mv a.txt /archive/
Gotcha: CMD's move can't move a folder to another drive; Move-Item and mv can. mv overwrites without asking (mv -i asks).
Rename a file
ren old.txt new.txt
ren old.txt new.txt
Rename-Item old.txt new.txt
Aliases: ren, rni
mv old.txt new.txt
Gotcha: CMD renames by wildcard (ren *.txt *.bak); Rename-Item doesn't: pipe files in with -NewName { $_.Name -replace '\.txt$','.bak' }. Linux has no rename command in coreutils; mv renames one file.
Delete a file
del file.txt
rm file.txt
Remove-Item file.txt
Aliases: del, rm, erase, ri
rm file.txt
Gotcha: None of these use the Recycle Bin. del *.* asks "Are you sure?"; rm *.* doesn't (and on Linux *.* only matches names containing a dot).
Delete a folder and everything in it
rmdir /s /q folder
Aliases: rd /s /q
deltree did this in MS-DOS; it's gone since Windows NT.
rm folder -r -fo
Remove-Item folder -Recurse -Force
Aliases: rm, rmdir, del, rd, ri
rm -rf folder
Gotcha: All three delete immediately with no undo and, with /q, -Force or -f, without asking. -Force is needed for hidden and read-only files. Double-check the path; a stray space in rm -rf / tmp is the classic disaster.
Create a folder (with parent folders)
mkdir a\b\c
Aliases: md
mkdir a\b\c
New-Item -ItemType Directory a\b\c
Aliases: mkdir, md
mkdir -p a/b/c
Gotcha: CMD and PowerShell create missing parent folders automatically; bash needs -p (which also stops the error when the folder exists). New-Item errors if it exists unless you add -Force.
Create an empty file (or update its time)
type nul > file.txt
ni file.txt
New-Item file.txt
Aliases: ni
touch file.txt
Gotcha: touch only updates the time of an existing file. type nul > and New-Item -Force empty an existing file, so check first. To update a time in PowerShell: (Get-Item file.txt).LastWriteTime = Get-Date.
Show a file's size
dir file.iso
(gi file.iso).Length
(Get-Item file.iso).Length
ls -lh file.iso
Gotcha: Length is in bytes; divide with PowerShell's size literals, (Get-Item f).Length / 1GB. ls -h prints human-readable sizes.
View a file's attributes or permissions
attrib file.txt
icacls file.txt shows permissions.
(gi file.txt).Attributes
(Get-Item file.txt).Attributes
Get-Acl for permissions.
ls -l file.txt
stat file.txt shows everything.
Gotcha: Windows has attributes (read-only, hidden, archive, system) plus ACLs; Linux has an owner, a group and rwx bits (and optional ACLs via getfacl).
Make a file read-only
attrib +r file.txt
(gi file.txt).IsReadOnly = $true
(Get-Item file.txt).IsReadOnly = $true
chmod a-w file.txt
Gotcha: On Windows read-only is an attribute anyone with permission can clear; on Linux removing write permission is a permission change, and root can still write.
Gotcha: The argument order is reversed: mklink and New-Item take the link first, ln -s takes the target first. On Windows symbolic links need an elevated prompt or Developer Mode; junctions (/j) don't.
Use wildcards in file names
dir *.txt
gci *.txt
Get-ChildItem -Filter *.txt
ls *.txt
Gotcha: bash expands wildcards before the command runs (so a command never sees *.txt), and it's case-sensitive. On Windows, *.htm can also match .html files where short 8.3 names exist, because those are checked too; that applies to dir and -Filter.

Moving around the file system: folders, drives, paths and completion.

TaskCMDPowerShellLinux (bash)
Change to another folder
cd C:\Users
cd /d D:\Data to change drive too.
cd C:\Users
Set-Location C:\Users
Aliases: cd, sl, chdir
cd /home
Gotcha: In CMD, cd D:\Data doesn't switch drives unless you add /d; PowerShell and bash just go there.
Go up one folder
cd..
cd ..
Set-Location ..
cd ..
Gotcha: CMD accepts cd.. without a space, and PowerShell has a built-in cd.. function; bash needs the space.
Go to your home folder
cd %USERPROFILE%
cd ~
Set-Location ~
cd
Gotcha: In bash, cd on its own goes home; in CMD it prints the current folder instead.
Go back to the previous folderNo built-in way; use pushd and popd.
cd -
Set-Location -
cd -
Gotcha: cd - (and cd + to go forward again) works in PowerShell 7; Windows PowerShell 5.1 doesn't have it.
Added in PowerShell 6.2.
Show the current folder
cd
Or echo %CD%
pwd
Get-Location
Aliases: pwd, gl
Also the $PWD variable.
pwd
Gotcha: In CMD, cd with no argument prints the folder; in bash it takes you home instead.
Remember a folder, go elsewhere, come back
pushd D:\Logs … popd
pushd D:\Logs … popd
Push-Location D:\Logs … Pop-Location
Aliases: pushd, popd
pushd /var/log … popd
Gotcha: CMD's pushd to a \\server\share path maps a temporary drive letter and popd removes it. bash's pushd prints the folder stack each time.
Switch drives or list them
D:
fsutil fsinfo drives lists them (elevated prompt may be needed).
Get-PSDrive -PSProvider FileSystem
D: switches drive.
cd /mnt/d
lsblk or findmnt lists disks and mounts.
Gotcha: Linux has no drive letters: every disk is mounted somewhere under / (under WSL, Windows drives appear as /mnt/c, /mnt/d).
Write a path
C:\Users\ann\file.txt
C:\Users\ann\file.txt
Forward slashes work too on Windows.
/home/ann/file.txt
Gotcha: bash treats \ as an escape character, so a pasted Windows path loses its backslashes unless quoted. Linux paths are case-sensitive.
Complete a file or command name
Tab
Repeated Tab cycles through matches.
Tab
Ctrl+Space shows every match as a menu (PSReadLine).
Tab
Tab twice lists all matches.
Gotcha: CMD and PowerShell cycle through complete names on each Tab; bash completes as far as it can, then lists the choices on a second Tab.

Reading files, finding text, sorting, counting and comparing.

TaskCMDPowerShellLinux (bash)
Show a file's contents
type file.txt
cat file.txt
Get-Content file.txt
Aliases: gc, cat, type
cat file.txt
Gotcha: Get-Content returns one string per line (objects you can index: (gc f)[0]); use -Raw for the whole file as one string.
Page through a long file
more file.txt
gc file.txt | more
Get-Content file.txt | Out-Host -Paging
less file.txt
Gotcha: more only goes forward; less scrolls both ways and searches with /. Out-Host -Paging doesn't work in the PowerShell ISE.
Show the first lines of a fileNo built-in way; use powershell -c "Get-Content file.txt -TotalCount 10".
gc file.txt -Head 10
Get-Content file.txt -TotalCount 10
-Head and -First are aliases of -TotalCount.
head -n 10 file.txt
Gotcha: head defaults to 10 lines; Get-Content has no default and reads the whole file without -TotalCount.
Show the last lines of a fileNo built-in way; use powershell -c "Get-Content file.txt -Tail 10".
gc file.txt -Tail 10
Get-Content file.txt -Tail 10
tail -n 10 file.txt
Gotcha: tail defaults to 10 lines; Get-Content -Tail needs a number.
Watch a log file as it growsNo built-in way; use PowerShell's Get-Content -Wait.
gc app.log -Tail 20 -Wait
Get-Content app.log -Tail 20 -Wait
tail -f app.log
Gotcha: Get-Content -Wait checks for new lines about once a second. tail -F (capital) also follows a log after it's rotated; tail -f stays on the old file. Stop either with Ctrl+C.
Find lines containing text
findstr /i "error" app.log
sls error app.log
Select-String -Pattern error -Path app.log
Aliases: sls
grep -i error app.log
Gotcha: Select-String ignores case by default (-CaseSensitive to match it); grep and findstr are case-sensitive unless you add -i or /i. findstr's regular expressions are very limited; Select-String uses .NET regex and grep POSIX (grep -E or -P for more).
Find text in all files under a folder
findstr /s /i "error" *.log
gci -r -Filter *.log | sls error
Get-ChildItem -Recurse -Filter *.log | Select-String error
grep -ri error --include='*.log' .
Gotcha: findstr /s and GNU grep -r search below the current folder when none is given. Select-String output includes the file name and line number, like grep -rn.
The two find commands
find "error" app.log
CMD's find searches for text in files.
find.exe "error" app.log
There's no find alias, so this is CMD's text search.
find /var/log -name '*.log'
Linux find searches for files.
Gotcha: Same name, different jobs: on Windows find looks for text inside files; on Linux find looks for files. Under WSL or Git Bash on Windows, which one runs depends on your PATH.
Sort lines
sort names.txt
gc names.txt | sort
Get-Content names.txt | Sort-Object
Aliases: sort
sort names.txt
Gotcha: Sort-Object can sort objects by property (Sort-Object Length). sort orders by the current locale; LC_ALL=C sort gives plain byte order.
The sort alias exists only on Windows; on Linux PowerShell runs the native sort.
Remove duplicate linesNo documented option in sort.exe; use PowerShell.
gc names.txt | sort -Unique
Get-Content names.txt | Sort-Object -Unique
sort -u names.txt
Gotcha: uniq and Get-Unique only drop duplicates that are next to each other, so sort first. Sort-Object -Unique ignores case; sort -u doesn't.
Count lines (or words)
find /c /v "" file.txt
gc file.txt | measure -Line
Get-Content file.txt | Measure-Object -Line -Word -Character
wc -l file.txt
Gotcha: find /c /v "" counts lines that don't match nothing, i.e. all of them. (Get-Content file.txt).Count also counts lines. wc -l counts newline characters, so a last line without one isn't counted.
Compare two files
fc a.txt b.txt
fc /b compares binary files.
Compare-Object (gc a.txt) (gc b.txt)
Aliases: compare, diff
diff a.txt b.txt
diff -u for the unified format.
Gotcha: Compare-Object compares sets of lines, not positions: it reports lines only in one file (<= or =>), ignoring order unless you add -SyncWindow 0. diff and fc show where the changes are. The Text Diff tool on this site shows both side by side.
The diff alias exists only on Windows; on Linux PowerShell runs the native diff.
Show a folder tree
tree /f
tree /f
tree.com works in PowerShell too; there's no cmdlet.
tree
Often not installed: apt install tree. find . works everywhere.
Gotcha: Without /f, Windows tree shows folders only; Linux tree shows files by default (tree -d for folders only).
Replace text in a fileNo built-in way; use PowerShell or a text editor.
(gc f.txt) -replace 'old','new' | sc f.txt
(Get-Content f.txt) -replace 'old','new' | Set-Content f.txt
sed -i 's/old/new/g' f.txt
Gotcha: Keep the parentheses in PowerShell: they read the whole file before Set-Content writes it, otherwise the file is emptied while being read. -replace is a regex and replaces every match. On macOS, sed -i needs an argument: sed -i '' 's/old/new/g' f.txt.
Pick a column out of CSV or delimited text
for /f "tokens=2 delims=," %a in (users.csv) do @echo %a
Import-Csv users.csv | select Name
Import-Csv users.csv | Select-Object Name
cut -d, -f2 users.csv
awk -F, '{print $2}' for more control.
Gotcha: Import-Csv understands quoted fields and headers; cut, awk and for /f split on every comma, even inside quotes. Use the CSV / JSON converter on this site for messy files.

Running and stopping programs, background jobs, services and schedules.

TaskCMDPowerShellLinux (bash)
List running processes
tasklist
gps
Get-Process
Aliases: gps, ps
ps aux
Gotcha: Get-Process objects can be sorted and filtered (gps | sort CPU -Desc | select -First 10); ps aux is text. top or htop on Linux gives a live view, like Task Manager.
The ps alias exists only on Windows; on Linux PowerShell runs the native ps.
Find a specific process
tasklist /fi "imagename eq notepad.exe"
gps notepad
Get-Process -Name notepad
pgrep -a notepad
Gotcha: Get-Process -Name takes the name without .exe; tasklist filters need it. ps aux | grep notepad also matches the grep itself; pgrep doesn't.
Stop a process
taskkill /im notepad.exe /f
taskkill /pid 1234 by process ID.
kill -Name notepad -Force
Stop-Process -Name notepad -Force
Aliases: kill, spps
kill 1234
pkill notepad by name; kill -9 to force.
Gotcha: Linux kill politely asks a process to exit (SIGTERM) and kill -9 forces it; Windows' taskkill without /f asks, with /f forces. PowerShell's kill is Stop-Process and takes -Id or -Name, not -9.
Start a program or open a file
start notepad
start report.pdf opens it in the default app.
start notepad
Start-Process notepad
Aliases: start, saps
Invoke-Item report.pdf (ii) opens a file.
xdg-open report.pdf
macOS: open report.pdf
Gotcha: In CMD, start's first quoted argument is the window title: start "" "C:\My App\app.exe". Start-Process doesn't have that trap.
Run a command in the background
start /b backup.cmd
Start-Job { .\backup.ps1 }
PowerShell 7: .\backup.ps1 & (Get-Job, Receive-Job).
./backup.sh &
jobs, fg and bg manage it; nohup keeps it running after logout.
Gotcha: A background bash job dies when the terminal closes unless you use nohup, setsid or tmux. PowerShell jobs run in a separate process, so they don't see variables from your session ($using:var does).
The & background operator was added in PowerShell 6.
List services
sc query
net start lists running ones.
Get-Service
Aliases: gsv
systemctl list-units --type=service
Gotcha: Get-Service lists stopped services too; sc query only running ones unless you add state= all.
Start, stop or restart a service
net start Spooler
net stop Spooler; sc start / sc stop also work.
Restart-Service Spooler
Start-Service, Stop-Service.
sudo systemctl restart cups
start, stop, status.
Gotcha: In Windows PowerShell, sc is an alias of Set-Content, not the service tool: type sc.exe. Windows services have a name and a display name; the cmdlets accept either with -Name or -DisplayName.
Make a service start at boot
sc config Spooler start= auto
Set-Service Spooler -StartupType Automatic
sudo systemctl enable cups
--now starts it as well.
Gotcha: sc needs the space after the equals sign (start= auto); without it the command fails. systemctl enable doesn't start the service until you add --now or reboot.
Run something on a schedule
schtasks /create /sc daily /st 02:00 /tn Backup /tr C:\Scripts\backup.cmd
Register-ScheduledTask -TaskName Backup -Action (New-ScheduledTaskAction -Execute C:\Scripts\backup.cmd) -Trigger (New-ScheduledTaskTrigger -Daily -At 2am)
crontab -e
Then a line like: 0 2 * * * /home/ann/backup.sh
Gotcha: Scheduled tasks and cron jobs run without your session: no mapped drives, a minimal PATH, and a different current folder. Use full paths. The Cron Expression tool on this site explains cron schedules.
List scheduled tasks
schtasks /query
Get-ScheduledTask
crontab -l
systemctl list-timers for systemd timers.
Gotcha: crontab -l shows only your own jobs; system jobs live in /etc/crontab, /etc/cron.d and systemd timers.
Wait a few seconds
timeout /t 5
Start-Sleep 5
Start-Sleep -Seconds 5
Aliases: sleep
sleep 5
Gotcha: timeout fails when input is redirected (in some scheduled tasks); add /nobreak, or use ping -n 6 127.0.0.1 >nul as the old workaround.

Addresses, connectivity, DNS, ports, routes and downloads.

TaskCMDPowerShellLinux (bash)
Show IP addresses
ipconfig
ipconfig /all for DNS servers, MAC and DHCP.
Get-NetIPConfiguration
Get-NetIPAddress for every address.
ip addr
Aliases: ip a
Gotcha: ifconfig is the old Linux command (net-tools) and is missing on many current distros; ip addr replaces it. On Linux ipconfig doesn't exist at all.
Ping a host
ping example.com
ping -t to keep going, -n 10 for ten.
Test-Connection example.com
-Count 10; PowerShell 7: -Repeat.
ping -c 4 example.com
Gotcha: Windows ping stops after 4 pings; Linux ping keeps going until Ctrl+C unless you give -c. Windows PowerShell's Test-Connection returns objects and is slow to time out.
Trace the route to a host
tracert example.com
Test-NetConnection example.com -TraceRoute
traceroute example.com
tracepath needs no root; mtr combines ping and traceroute.
Gotcha: tracert uses ICMP; Linux traceroute sends UDP by default, which firewalls treat differently (traceroute -I for ICMP).
Look up a DNS name
nslookup example.com
Resolve-DnsName example.com
-Type MX for mail servers.
dig example.com
dig MX example.com; host example.com is shorter.
Gotcha: nslookup has its own resolver logic and can disagree with what applications see; Resolve-DnsName uses the Windows resolver (hosts file and cache included). The DNS Lookup tool on this site compares public resolvers.
Clear the DNS cache
ipconfig /flushdns
Clear-DnsClientCache
resolvectl flush-caches
On systemd-resolved systems; others may have no cache.
Gotcha: Many Linux systems don't cache DNS at all unless systemd-resolved, dnsmasq or nscd is running, so there may be nothing to flush.
Show network connections
netstat -ano
Get-NetTCPConnection
ss -tunap
netstat is the older net-tools command.
Gotcha: netstat -ano shows the process ID; netstat -b shows the program name but needs an elevated prompt. ss -p only shows processes you own unless run with sudo.
See what's listening on a port
netstat -ano | findstr :443
Get-NetTCPConnection -LocalPort 443 -State Listen
OwningProcess is the PID: Get-Process -Id …
sudo ss -ltnp 'sport = :443'
Or: sudo lsof -i :443
Gotcha: findstr :443 also matches :4430 and remote ports; filter more tightly or use Get-NetTCPConnection.
Test whether a TCP port is reachableNo built-in way (the telnet client is an optional feature); use PowerShell's Test-NetConnection.
tnc example.com -Port 443
Test-NetConnection example.com -Port 443
Aliases: tnc
nc -zv example.com 443
Gotcha: Test-NetConnection pings first, which adds a delay and a misleading warning when ICMP is blocked; TcpTestSucceeded is the answer that matters.
Download a file
curl -o file.zip https://example.com/file.zip
curl.exe is built into Windows 10 1803 and later.
iwr https://example.com/file.zip -OutFile file.zip
Invoke-WebRequest https://example.com/file.zip -OutFile file.zip
Aliases: iwr
curl -O https://example.com/file.zip
wget https://… also works where installed.
Gotcha: In Windows PowerShell 5.1, curl and wget are aliases of Invoke-WebRequest, so curl -o fails with a parameter error: type curl.exe. PowerShell 7 removed those aliases.
Windows PowerShell 5.1's Invoke-WebRequest is slow with its progress bar on: $ProgressPreference = 'SilentlyContinue' speeds it up.
See a website's response headers
curl -I https://example.com
(iwr https://example.com -Method Head).Headers
(Invoke-WebRequest https://example.com -Method Head).Headers
curl -I https://example.com
Gotcha: curl -I sends a HEAD request, which some servers answer differently from a normal GET; curl -sD - -o /dev/null URL shows the headers of a real GET. The Security Headers tool on this site grades them.
Find your public IP address
curl https://tclient.com/ip
irm https://tclient.com/ip
Invoke-RestMethod https://tclient.com/ip
curl https://tclient.com/ip
Gotcha: ipconfig and ip addr show your private address on the local network; behind a router, the internet sees the router's public address instead.
Show the computer's name
hostname
hostname
Also $env:COMPUTERNAME.
hostname
hostnamectl shows and sets it on systemd systems.
Gotcha: %COMPUTERNAME% and $env:COMPUTERNAME are upper case and limited to 15 characters (the NetBIOS name); hostname gives the full name.
Show the ARP table (IP to MAC)
arp -a
Get-NetNeighbor
ip neigh
arp -n on systems with net-tools.
Gotcha: Entries only exist for hosts you've recently talked to; ping a host first to see its MAC address.
Show the routing table
route print
Get-NetRoute
ip route
route -n on systems with net-tools.
Gotcha: route print lists IPv4 and IPv6 together; ip route shows IPv4 only (ip -6 route for IPv6).

Who you are, accounts and groups, running as administrator, file permissions.

TaskCMDPowerShellLinux (bash)
Show who you're logged in as
whoami
whoami
Also $env:USERNAME.
whoami
id shows the user and group IDs too.
Gotcha: Windows whoami prints DOMAIN\user; whoami /upn and /fqdn give other forms. $env:USERNAME doesn't include the domain.
Show your group memberships
whoami /groups
whoami /groups
id
groups lists names only.
Gotcha: Group changes only apply after you log on again on both systems (on Linux, newgrp or a new session).
List local user accounts
net user
Get-LocalUser
getent passwd
cut -d: -f1 /etc/passwd for names only.
Gotcha: getent passwd includes dozens of system accounts; real users usually have a UID of 1000 or more.
Get-LocalUser is part of Windows PowerShell 5.1; PowerShell 7 may load it through Windows PowerShell compatibility and show a notice.
Create a local user
net user bob * /add
The * prompts for the password.
New-LocalUser bob -Password (Read-Host -AsSecureString)
sudo useradd -m bob && sudo passwd bob
Debian/Ubuntu: sudo adduser bob asks for everything.
Gotcha: Don't type the password on the command line (net user bob P@ss /add): it ends up in history and in process listings.
Add a user to a group
net localgroup Administrators bob /add
Add-LocalGroupMember -Group Administrators -Member bob
sudo usermod -aG sudo bob
The admin group is wheel on Fedora and RHEL.
Gotcha: usermod -G without -a replaces all the user's groups instead of adding one. The new membership applies at the user's next logon.
Run a command as administrator
sudo cmd
Windows 11 24H2 and later, once enabled. Otherwise: right-click, Run as administrator.
Start-Process pwsh -Verb RunAs
sudo command
sudo -i for a root shell.
Gotcha: runas /user:Administrator switches to another account; it doesn't elevate your own. Sudo for Windows is off by default: turn it on in Settings > System > Advanced (Enable sudo).
Check whether you're elevated
net session >nul 2>&1 && echo Elevated
([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole('Administrators')
[ "$(id -u)" -eq 0 ] && echo root
Gotcha: Being in the Administrators group isn't enough on Windows: with UAC the prompt only has admin rights after Run as administrator.
View file permissions
icacls file.txt
Get-Acl file.txt | fl
Get-Acl file.txt | Format-List
ls -l file.txt
getfacl for extended ACLs.
Gotcha: Windows uses ACLs of allow and deny entries per user or group, inherited from folders; Linux shows read, write and execute for owner, group and everyone else (rwxr-x---).
Change file permissions
icacls file.txt /grant bob:(R)
icacls file.txt /grant 'bob:(R)'
Set-Acl works with an ACL object you build first.
chmod 640 file.txt
chmod u+x script.sh adds execute for the owner.
Gotcha: In PowerShell, quote icacls permissions: (R) is otherwise read as a PowerShell expression. chmod numbers are owner/group/other: 6 = read+write, 4 = read, 0 = nothing.
Change a file's owner
icacls file.txt /setowner bob
takeown /f file.txt makes you the owner.
icacls file.txt /setowner bob
sudo chown bob:staff file.txt
chown -R for a whole folder.
Gotcha: chown takes user:group in one argument; on Windows the group isn't set this way. Both need administrator or root rights to give a file away.

Free space, OS and hardware details, environment variables, time, power and history.

TaskCMDPowerShellLinux (bash)
Show free disk space
dir C:\
The last line shows bytes free.
Get-Volume
Get-PSDrive C for one drive.
df -h
Gotcha: df -h shows every mounted filesystem, including small temporary ones (tmpfs); df -h / for just the root.
Show a folder's total size
dir /s D:\Data
The total is at the end.
(gci D:\Data -r -File | measure Length -Sum).Sum / 1GB
(Get-ChildItem D:\Data -Recurse -File | Measure-Object Length -Sum).Sum / 1GB
du -sh /data
Gotcha: du shows space used on disk, which differs from the sum of file sizes (block size, sparse files); Get-ChildItem sums the file lengths.
Show system information
systeminfo
Get-ComputerInfo
hostnamectl
uname -a for the kernel; cat /etc/os-release for the distribution.
Gotcha: Get-ComputerInfo is slow (it collects everything); pick what you need: Get-ComputerInfo -Property OsName,OsVersion.
Show the OS version
ver
[Environment]::OSVersion
$PSVersionTable shows the PowerShell version.
cat /etc/os-release
lsb_release -a where installed.
Gotcha: ver shows the build number (10.0.26100) but not the edition or the marketing name; winver shows those in a window.
Show how long the system has been up
systeminfo | find "Boot Time"
Get-Uptime
Windows PowerShell: (Get-Date) - (Get-CimInstance Win32_OperatingSystem).LastBootUpTime
uptime
Gotcha: With Fast Startup on, shutting down Windows doesn't reset the uptime; only a restart does.
Get-Uptime was added in PowerShell 6.
Show CPU and memory
systeminfo | findstr /c:"Total Physical Memory"
Get-CimInstance Win32_Processor
Get-CimInstance Win32_OperatingSystem | select FreePhysicalMemory, TotalVisibleMemorySize
lscpu
free -h for memory.
Gotcha: wmic, the old CMD way, is deprecated and being removed from Windows; use the CIM cmdlets. Linux free counts cache as "used"; the available column is what matters.
List environment variables
set
gci env:
Get-ChildItem Env:
printenv
Aliases: env
Gotcha: set in bash also prints shell variables and functions; printenv shows only exported variables.
Read an environment variable
echo %PATH%
$env:PATH
echo $PATH
Gotcha: Linux variable names are case-sensitive ($PATH, not $path), and PATH entries are separated by : rather than ;.
Set an environment variable
set NAME=value
setx NAME value saves it for new windows.
$env:NAME = 'value'
[Environment]::SetEnvironmentVariable('NAME','value','User') saves it.
export NAME=value
Add it to ~/.bashrc to keep it.
Gotcha: In CMD, set NAME = value creates a variable called "NAME " with the value " value": no spaces around =. setx doesn't change the current window and cuts values at 1,024 characters.
Show the date and time
echo %DATE% %TIME%
date /t and time /t
Get-Date
Get-Date -Format o for ISO 8601.
date
date -u for UTC; date +%F for 2026-10-26.
Gotcha: %DATE% follows the regional settings, so scripts that cut it apart break on other machines. Get-Date returns a real date you can calculate with. The Unix Timestamp tool on this site converts between formats.
Restart the computer
shutdown /r /t 0
Restart-Computer
sudo reboot
systemctl reboot
Gotcha: shutdown without /t waits 30 seconds on Windows; Linux shutdown -r without a time waits one minute (shutdown -r now).
Shut down the computer
shutdown /s /t 0
Stop-Computer
sudo shutdown -h now
systemctl poweroff
Gotcha: With Fast Startup on, Windows shutdown /s hibernates the kernel; shutdown /s /full does a full shutdown.
Clear the screen
cls
cls
Clear-Host
Aliases: cls, clear
clear
Ctrl+L
Show or search command history
doskey /history
F7 shows a list.
h
Get-History
Aliases: h, history
Ctrl+R searches history (PSReadLine).
history
Ctrl+R searches backwards.
Gotcha: Get-History only covers the current session; PSReadLine keeps everything in a file ((Get-PSReadLineOption).HistorySavePath). CMD forgets history when the window closes.

Variables, quoting, conditions, loops, functions, exit codes, pipes and redirection.

TaskCMDPowerShellLinux (bash)
Write a comment
rem comment
Aliases: :: comment
# comment
<# … #> for a block.
# comment
Gotcha: :: is a label trick, not a real comment: inside a parenthesised block it can cause errors, so use rem there.
Set and use a variable
set name=Ann … echo %name%
$name = 'Ann' … $name
name=Ann … echo "$name"
Gotcha: bash allows no spaces around = (name = Ann runs a command called name). In CMD, variables inside a ( … ) block are expanded once when the block is read; use setlocal enabledelayedexpansion and !name!.
Quote a string
echo "Hello %name%"
Escape special characters with ^ outside quotes.
"Hello $name" vs 'Hello $name'
Escape with a backtick: `$
"Hello $name" vs 'Hello $name'
Escape with a backslash: \$
Gotcha: CMD has only double quotes and passes them on to the program. In PowerShell and bash, single quotes are literal and double quotes expand variables, but the escape character differs (` vs \).
If / else
if exist file.txt (echo yes) else (echo no)
if (Test-Path file.txt) { 'yes' } else { 'no' }
if [ -f file.txt ]; then echo yes; else echo no; fi
Gotcha: bash needs the spaces inside [ ] and the closing fi. In CMD, else must be on the same line as the closing parenthesis.
Compare numbers and strings
if %n% GEQ 8 echo big
EQU NEQ LSS LEQ GTR GEQ; if /i for case-insensitive strings.
if ($n -ge 8) { 'big' }
-eq -ne -lt -le -gt -ge; -like and -match for patterns.
if [ "$n" -ge 8 ]; then echo big; fi
[[ $s == foo* ]] for patterns.
Gotcha: In PowerShell and CMD, > is redirection, not "greater than": if ($n > 8) creates a file named 8. PowerShell's -eq ignores case for strings (-ceq doesn't).
Loop over files
for %f in (*.txt) do echo %f
Write %%f inside a .bat file.
foreach ($f in gci *.txt) { $f.Name }
Get-ChildItem *.txt | ForEach-Object { $_.Name }
Aliases: %, foreach
for f in *.txt; do echo "$f"; done
Gotcha: The single % works at the prompt but batch files need %%f. In bash, quote "$f" or names with spaces split into several words.
Loop a number of times
for /l %i in (1,1,10) do echo %i
foreach ($i in 1..10) { $i }
for i in {1..10}; do echo $i; done
Gotcha: CMD's /l takes start, step, end; 1..10 and {1..10} include both ends.
While loop
:loop … if %n% LSS 5 goto loop
CMD has no while; use goto.
while ($n -lt 5) { $n++ }
while [ $n -lt 5 ]; do n=$((n+1)); done
Gotcha: bash arithmetic needs $(( )); n=n+1 assigns the text "n+1".
Define and call a function
call :greet Ann … :greet echo Hello %1 goto :eof
function Greet($Name) { "Hello $Name" } … Greet Ann
greet() { echo "Hello $1"; } … greet Ann
Gotcha: Call PowerShell functions like commands: Greet Ann Bob, not Greet('Ann','Bob'), which passes a single array. In CMD, end the function with goto :eof or it runs into the next label.
Read a script's arguments
%1 %2 … %*
param($Path) or $args[0]
$1 $2 … "$@"
Gotcha: %~1 removes surrounding quotes in CMD. In bash, "$@" keeps each argument intact; $* joins them.
Check the last exit code
echo %ERRORLEVEL%
exit /b 3 sets it.
$LASTEXITCODE
$? is $true or $false; exit 3 sets it.
echo $?
exit 3 sets it.
Gotcha: $? is true/false in PowerShell but a number in bash. $LASTEXITCODE only changes when a native program runs, not after cmdlets. robocopy is the exception everywhere: codes below 8 mean success.
Run a script file
backup.bat
From another batch file: call backup.bat
.\backup.ps1
If blocked: Set-ExecutionPolicy RemoteSigned -Scope CurrentUser
./backup.sh
After chmod +x backup.sh, or: bash backup.sh
Gotcha: PowerShell won't run a script from the current folder without .\, and execution policy blocks scripts on Windows clients by default. A batch file that runs another without call never returns. bash scripts need a #!/bin/bash first line and the execute bit.
Windows Server's default execution policy is RemoteSigned; Windows client editions default to Restricted.
Pipe one command into another
dir | find ".txt"
gci | where Length -gt 1MB
Get-ChildItem | Where-Object Length -gt 1MB
Aliases: where, ?
ls -l | grep .txt
Gotcha: The big one: PowerShell pipes objects, so you filter on properties (Length, Name) instead of parsing text. CMD and bash pipe lines of text. Mixing them in PowerShell (gci | findstr txt) works, but findstr sees formatted text, not objects.
Send output (and errors) to a file
cmd > out.txt 2>&1
>> appends.
cmd *> out.txt
Out-File -Encoding utf8 to choose the encoding.
cmd > out.txt 2>&1
&> out.txt is the short form.
Gotcha: Windows PowerShell 5.1's > writes UTF-16 LE, which many tools can't read; PowerShell 7 writes UTF-8 without a BOM; CMD writes the console code page. In bash, 2>&1 must come after > out.txt.
*> (all streams) needs PowerShell 3 or later.
Throw output away
cmd > nul 2>&1
cmd | Out-Null
Or > $null
cmd > /dev/null 2>&1
Gotcha: In PowerShell, > nul creates a file only on Linux; $null works everywhere.
Run the next command only if the first worked (&& and ||)
build && deploy || echo failed
build && deploy || 'failed'
PowerShell 7 and later.
build && deploy || echo failed
Gotcha: Windows PowerShell 5.1 doesn't support && and ||; use if ($?) { … } there, or ; to run commands regardless.
&& and || were added in PowerShell 7.0.
Store a command's output in a variable
for /f %i in ('hostname') do set h=%i
$h = hostname
h=$(hostname)
Gotcha: PowerShell captures objects (or an array of lines from native programs); bash captures text and strips trailing newlines.
Ask the user for input
set /p name=Name?
$name = Read-Host 'Name?'
read -p 'Name? ' name
Gotcha: Read-Host -AsSecureString hides typing (passwords); read -s does the same in bash.

Finding, installing, upgrading and removing software from the command line.

TaskCMDPowerShellLinux (bash)
Gotcha: apt searches the package lists you downloaded last; run sudo apt update first on a fresh system.
Fedora/RHEL: dnf search. Arch: pacman -Ss. macOS: brew search.
Install a package
winget install Microsoft.VisualStudioCode
winget install Microsoft.VisualStudioCode
Install-Module for PowerShell modules.
sudo apt install code
Gotcha: Use the exact winget ID (--id … --exact) in scripts: names can match several packages. apt needs sudo; with winget, installers that need administrator rights show a UAC prompt.
Fedora/RHEL: sudo dnf install. Arch: sudo pacman -S. macOS: brew install (no sudo).
Upgrade everything
winget upgrade --all
winget upgrade --all
Update-Module for PowerShell modules.
sudo apt update && sudo apt upgrade
Gotcha: apt update only refreshes the lists; apt upgrade installs the updates. winget upgrade without --all only lists what's available.
Fedora/RHEL: sudo dnf upgrade. Arch: sudo pacman -Syu. macOS: brew upgrade.
Remove a package
winget uninstall Microsoft.VisualStudioCode
winget uninstall Microsoft.VisualStudioCode
Uninstall-Module for PowerShell modules.
sudo apt remove code
apt purge also deletes its system settings.
Gotcha: apt remove keeps configuration files; purge deletes them. Neither touches files in your home folder.
Fedora/RHEL: sudo dnf remove. Arch: sudo pacman -R. macOS: brew uninstall.
List installed packages
winget list
winget list
Get-Package (Windows PowerShell) also lists MSI installs.
apt list --installed
dpkg -l is the older form.
Gotcha: winget list shows everything in Apps & features, including software it didn't install; the Source column is filled in when winget can match an entry to a repository package.
Fedora/RHEL: dnf list installed or rpm -qa. Arch: pacman -Q. macOS: brew list.
Show details of a package
winget show Microsoft.VisualStudioCode
winget show Microsoft.VisualStudioCode
apt show code
Gotcha: apt show describes the version in the repository, which may be newer than the one installed (apt policy code shows both).
Fedora/RHEL: dnf info. Arch: pacman -Si. macOS: brew info.

Getting help on a command and finding the command you need.

TaskCMDPowerShellLinux (bash)
Get help on a command
dir /?
help dir does the same.
Get-Help Get-ChildItem -Full
Aliases: help, man
Get-ChildItem -? shows a summary.
man ls
ls --help for a quick summary.
Gotcha: PowerShell's help is nearly empty until you run Update-Help (as administrator in Windows PowerShell 5.1); -Online opens the Microsoft Learn page instead.
PowerShell 7 can install help per user: Update-Help -Scope CurrentUser.
See examples of a command/? shows few examples; Microsoft Learn's command reference has more.
Get-Help Get-ChildItem -Examples
man ls
Look for the EXAMPLES section; tldr ls gives short examples if installed.
Gotcha: Many GNU man pages have no examples at all; info pages (info ls) are often more detailed.
Find a command by what it does
help
Lists the built-in CMD commands.
Get-Command *service*
Aliases: gcm
Get-Command -Verb Get -Noun *net*
apropos service
compgen -c lists every command.
Gotcha: PowerShell cmdlets follow Verb-Noun names, so guessing works: Get-*, Set-*, *-Service. apropos searches man page descriptions and needs mandb to have run.
Find where a command lives
where notepad
Get-Command notepad
Aliases: gcm
where.exe notepad
which notepad
type -a notepad also shows aliases and functions.
Gotcha: In PowerShell, where is an alias of Where-Object, so where notepad silently does nothing: type where.exe. Get-Command also tells you whether a name is an alias, function, cmdlet or program.

Opening, saving and quitting the usual terminal editors.

TaskCMDPowerShellLinux (bash)
Open a file in an editor
notepad file.txt
notepad file.txt
code file.txt opens VS Code where installed.
nano file.txt
vim file.txt, or vi on minimal systems.
Gotcha: The old DOS EDIT command was 16-bit and isn't in 64-bit Windows. On a Linux server without a desktop, nano is the friendliest choice; vi is almost always installed.
Save and quit
Ctrl+S, then Alt+F4
In Notepad.
Ctrl+S, then Alt+F4
In Notepad.
nano: Ctrl+O, Enter, Ctrl+X
vim: Esc, then :wq and Enter
Gotcha: vim starts in normal mode: press i to type, Esc to stop typing, then : commands. nano lists its shortcuts at the bottom (^ means Ctrl).
Quit without saving
Alt+F4, then Don't Save
Alt+F4, then Don't Save
vim: Esc, then :q! and Enter
nano: Ctrl+X, then N
Gotcha: :q on its own refuses to quit when there are changes; the ! discards them.
Gotcha: vim's / takes a regular expression, so special characters such as . and * need a backslash to be literal.
Edit a protected system file
Run as administrator, then notepad C:\Windows\System32\drivers\etc\hosts
Start-Process notepad C:\Windows\System32\drivers\etc\hosts -Verb RunAs
sudo nano /etc/hosts
sudoedit /etc/hosts uses your own editor settings.
Gotcha: Notepad opened without elevation shows the file but can't save it (it offers Save As instead). The hosts file is in a different place on each OS.