Command Line Interface Cheat Sheet

Windows CMD  Β·  PowerShell  Β·  Bash (Linux and macOS)  Β·  Git

How to read this sheet. Each row shows the same task in all three shells. Commands are in monospace; grey italics explain flags or name an alias for the same command. πŸ”’ needs administrator, root or sudo. ⚠ destructive; check before running. (Linux) or (macOS) marks a command that exists only on that platform. β˜… marks the everyday essentials. Click any command to copy it.

Everyday Essentials

The commands most people use every day, in short form. Click a task name for the full entry with more options and notes.

TaskCMDPowerShellBash
β˜… Change directory
cd C:\Users
cd ..\Desktop
cd "C:\Program Files"
Set-Location ~\Desktop
cd /home/user/docs
cd ~/Desktop
β˜… List files
dir
dir /A (include hidden)
Get-ChildItem (alias: ls, dir, gci)
ls -Force (include hidden)
ls
ls -la (long, incl. hidden)
β˜… Copy files
copy file.txt C:\Backup
copy *.txt D:\Backup
Copy-Item file.txt ~\Backup (alias: cp)
Copy-Item *.txt -Destination C:\Backup
cp file.txt ~/Backup
cp -i file.txt ~/Backup (prompt before overwrite)
β˜… Move or rename
move file.txt C:\New
ren old.txt new.txt
Move-Item file.txt C:\New (alias: mv)
Rename-Item old.txt new.txt
mv file.txt ~/new/
mv old.txt new.txt
β˜… Delete files
del oldfile.txt
del *.tmp
Remove-Item oldfile.txt (alias: rm, del)
Remove-Item *.tmp -WhatIf (dry run)
rm oldfile.txt
rm -i file.txt (confirm)
β˜… View file contents
type readme.txt
Get-Content readme.txt (alias: cat, type, gc)
cat readme.txt
less readme.txt (paginated; q to quit)
β˜… Find files
dir /S /B *.txt
where /R C:\Projects *.log
Get-ChildItem -Recurse -Filter *.txt
gci -r -Include *.log,*.txt
find . -name "*.txt"
find /home -type f -name "*.log"
β˜… Search text in files
findstr "error" log.txt
findstr /S /I "text" *.* (recursive, ignore case)
Select-String -Path log.txt -Pattern error (alias: sls)
sls error *.log -CaseSensitive
grep "error" log.txt
grep -ri "error" /var/log/ (recursive, ignore case)
β˜… List processes
tasklist
tasklist /V (verbose)
Get-Process (alias: ps, gps)
Get-Process -Name chrome
ps aux
ps aux | grep nginx
β˜… Kill process
taskkill /IM notepad.exe
taskkill /PID 1234 /F (force)
Stop-Process -Name notepad (alias: kill)
Stop-Process -Id 1234 -Force
kill 1234 (SIGTERM, polite)
kill -9 1234 (SIGKILL, force)
β˜… Ping host
ping google.com (4 packets)
ping -n 10 192.168.1.1
Test-Connection google.com
Test-Connection 8.8.8.8 -Count 5
ping google.com (until Ctrl+C)
ping -c 5 google.com
β˜… IP configuration
ipconfig
ipconfig /all (MAC, DNS, DHCP)
Get-NetIPConfiguration
Get-NetIPAddress -AddressFamily IPv4
ip addr (Linux; short form: ip a)
ifconfig (macOS; deprecated on Linux)
β˜… Show environment variables
set
set PATH (all starting with PATH)
Get-ChildItem Env: (or: dir env:)
$env:PATH
printenv
env
β˜… Command history
doskey /history
F7 (popup list)
Get-History (alias: h, history)
Get-Content (Get-PSReadLineOption).HistorySavePath (all sessions)
history
history 20 (last 20)
β˜… Get help
dir /?
help copy
Get-Help Get-Process -Examples
Get-Help *-Service (search by name)
man ls
ls --help

File and Directory Management

TaskCMDPowerShellBashNotes
β˜… Change directory
cd C:\Users
cd ..\Desktop
cd /d D:\Data (switch drive)
D: (switch drive only)
cd "C:\Program Files"
Set-Location ~\Desktop
cd - (previous dir, PS 6+)
cd /home/user/docs
cd ~/Desktop
cd - (previous dir)
cd (home)
cd .. goes to the parent. ~ is the home directory in PowerShell and Bash. CMD needs /d to change drive and directory at once.
β˜… List files
dir
dir /A (include hidden)
dir /S (recursive)
dir /B (bare names)
dir /O-D (newest first)
Get-ChildItem (alias: ls, dir, gci)
ls -Force (include hidden)
Get-ChildItem -Recurse
ls *.txt
ls
ls -la (long, incl. hidden)
ls -lh (readable sizes)
ls -lt (newest first)
ls -R (recursive)
Show current directory
cd (no arguments)
echo %CD%
Get-Location (alias: pwd)
$PWD
pwd
Create directory
mkdir MyReports
md Folder1\Folder2 (nested is fine)
mkdir ~/Projects/New
New-Item -ItemType Directory MyReports
mkdir MyReports
mkdir -p a/b/c (nested)
Remove directory
rmdir OldFolder (empty only)
rmdir /S /Q OldFolder (with contents, no prompt)
Remove-Item OldFolder -Recurse -Force
Remove-Item OldFolder -Recurse -WhatIf (preview)
rmdir OldFolder (empty only)
rm -r OldFolder
rm -rf OldFolder (no prompts)
⚠ Recursive deletes bypass the Recycle Bin / Trash. There is no undo.
Directory tree
tree C:\Projects
tree /F (include files)
tree /F (same tree.com as CMD)
Get-ChildItem -Recurse -Name
tree ~/Projects
tree -L 2 (limit depth)
tree is not preinstalled on most Linux distros or macOS: apt install tree, brew install tree.
β˜… Copy files
copy file.txt C:\Backup
copy *.txt D:\Backup
Copy-Item file.txt ~\Backup (alias: cp)
Copy-Item *.txt -Destination C:\Backup
cp file.txt ~/Backup
cp -i file.txt ~/Backup (prompt before overwrite)
Copy directories
xcopy C:\Src D:\Dst /E /I
robocopy C:\Src D:\Dst /E
robocopy C:\Src D:\Dst /MIR (mirror; deletes extras)
Copy-Item folder -Recurse -Destination dest
cp -r folder/ ~/dest
cp -a folder/ ~/dest (preserve attributes)
rsync -av src/ dest/
robocopy and rsync are the robust choices for large copies: both can resume and mirror. ⚠ /MIR and rsync --delete remove files at the destination.
β˜… Move or rename
move file.txt C:\New
ren old.txt new.txt
Move-Item file.txt C:\New (alias: mv)
Rename-Item old.txt new.txt
mv file.txt ~/new/
mv old.txt new.txt
β˜… Delete files
del oldfile.txt
del *.tmp
del /P file.txt (prompt)
Remove-Item oldfile.txt (alias: rm, del)
Remove-Item *.tmp -WhatIf (dry run)
rm oldfile.txt
rm -i file.txt (confirm)
rm *.tmp
⚠ No Recycle Bin. In PowerShell, -WhatIf previews any destructive cmdlet.
β˜… View file contents
type readme.txt
Get-Content readme.txt (alias: cat, type, gc)
cat readme.txt
less readme.txt (paginated; q to quit)
Create empty file
type nul > notes.txt
copy con notes.txt (type text, then Ctrl+Z, Enter)
New-Item -ItemType File notes.txt (alias: ni)
touch notes.txt
> notes.txt
touch also updates the timestamp of an existing file. New-Item errors if the file exists unless you add -Force.
β˜… Find files
dir /S /B *.txt
where /R C:\Projects *.log
Get-ChildItem -Recurse -Filter *.txt
gci -r -Include *.log,*.txt
gci -r | Where LastWriteTime -gt (Get-Date).AddDays(-1)
find . -name "*.txt"
find /home -type f -name "*.log"
find . -mtime -1 (modified in last day)
find . -size +100M
Which command runs
where python
Get-Command python
Get-Command ls (shows what an alias points to)
which python
type ls (shows aliases and builtins too)
command -v python
Compare files
fc file1.txt file2.txt
fc /B a.bin b.bin (binary)
Compare-Object (Get-Content a.txt) (Get-Content b.txt) (alias: diff)
diff file1.txt file2.txt
diff -u a.txt b.txt (unified format)
PowerShell's diff alias is not Unix diff: it compares sets of objects and ignores line order unless you add -SyncWindow 0.
β˜… Search text in files
findstr "error" log.txt
findstr /S /I "text" *.* (recursive, ignore case)
findstr /N "text" file.txt (line numbers)
Select-String -Path log.txt -Pattern error (alias: sls)
sls error *.log -CaseSensitive
gci -r *.log | sls error
grep "error" log.txt
grep -ri "error" /var/log/ (recursive, ignore case)
grep -n "text" file.txt (line numbers)
File permissions
icacls file.txt
icacls file.txt /grant User:F
Get-Acl file.txt
Set-Acl file.txt -AclObject $acl
icacls file.txt (works here too)
chmod 755 script.sh
chmod +x script.sh
chown user:group file.txt
πŸ”’ Changing permissions on files you do not own needs admin or sudo. Windows uses ACLs; Unix uses rwx bits.
File attributes
attrib +r file.txt (read-only)
attrib +h file.txt (hidden)
attrib -r -h file.txt
Set-ItemProperty file.txt IsReadOnly $true
(Get-Item file.txt).Attributes
chattr +i file.txt (immutable, Linux)
chattr -i file.txt
chflags hidden file.txt (macOS)
Unix has no hidden attribute: files whose names start with a dot are hidden by convention.
Symbolic links
mklink link.txt C:\target.txt
mklink /D linkdir C:\target
New-Item -ItemType SymbolicLink -Path link -Target target
ln -s target link
ln -s /path/to/dir linkdir
πŸ”’ Windows needs an admin prompt or Developer Mode to create symlinks. Bash argument order is target first, then link.
Compress / archive
tar -a -cf archive.zip folder (Windows 10 1803+)
compact /C file.txt (NTFS compression, not an archive)
Compress-Archive -Path folder -DestinationPath archive.zip
tar -czvf archive.tar.gz folder/
zip -r archive.zip folder/
gzip file.txt (replaces file with file.txt.gz)
bsdtar ships with Windows 10 and later and works in both CMD and PowerShell. It reads .zip, .tar.gz, .7z and more.
Extract
tar -xf archive.zip
tar -xf archive.tar.gz
expand archive.cab C:\dest (CAB only)
Expand-Archive archive.zip -DestinationPath dest\
unzip archive.zip
tar -xzvf archive.tar.gz
gunzip file.txt.gz
File hash / checksum
certutil -hashfile file.iso SHA256
Get-FileHash file.iso (SHA256 by default)
Get-FileHash file.iso -Algorithm MD5
sha256sum file.iso
md5sum file.iso
shasum -a 256 file.iso (macOS)
Open with default app
start report.pdf
start . (Explorer here)
start https://example.com
Invoke-Item report.pdf (alias: ii)
start . (alias of Start-Process)
xdg-open report.pdf (Linux)
open report.pdf (macOS)
open . (Finder here, macOS)
Clear screen
cls
Clear-Host (alias: cls, clear)
Ctrl+L
clear
Ctrl+L

Disk and Storage

TaskCMDPowerShellBashNotes
Free disk space
fsutil volume diskfree C:
wmic logicaldisk get name,size,freespace (wmic is deprecated)
Get-PSDrive -PSProvider FileSystem
Get-Volume
Get-CimInstance Win32_LogicalDisk | Select DeviceID,Size,FreeSpace
df -h
df -h /home (one filesystem)
wmic is deprecated and removed from recent Windows 11 builds. Prefer Get-CimInstance.
Disk and partition info
diskpart (interactive: list disk, list volume)
wmic diskdrive get model,size (deprecated)
Get-Disk
Get-Partition
Get-Volume
lsblk (Linux)
sudo fdisk -l (Linux)
diskutil list (macOS)
Folder size
dir /S C:\folder (total at the end)
(Get-ChildItem -Recurse folder | Measure-Object Length -Sum).Sum / 1MB
du -sh folder/
du -h --max-depth=1 . | sort -h (Linux)
du -sh * | sort -h
Check disk
chkdsk C:
chkdsk C: /F (fix errors; system drive needs a reboot)
Repair-Volume -DriveLetter C -Scan
Repair-Volume -DriveLetter C -OfflineScanAndFix
sudo fsck /dev/sda1 (unmount first)
diskutil verifyVolume / (macOS)
πŸ”’ Requires admin or sudo. Never run fsck on a mounted filesystem.
Format drive
format D: /FS:NTFS /Q
Format-Volume -DriveLetter D -FileSystem NTFS
sudo mkfs.ext4 /dev/sdb1
diskutil eraseDisk APFS Name disk2 (macOS)
⚠⚠ Destroys everything on the volume. Double-check the drive letter or device name first.
Mount / map drives
net use Z: \\server\share (map network drive)
net use Z: /delete
mountvol (list volume mount points)
New-PSDrive -Name Z -PSProvider FileSystem -Root \\server\share -Persist
Mount-DiskImage file.iso
Dismount-DiskImage file.iso
sudo mount /dev/sdb1 /mnt/usb
sudo umount /mnt/usb
mount (list mounts)

System and User Information

TaskCMDPowerShellBashNotes
Current user
whoami
echo %USERNAME%
whoami /groups
whoami
$env:USERNAME
[Environment]::UserName
whoami
echo $USER
id (uid, gid and groups)
Hostname
hostname
echo %COMPUTERNAME%
hostname
$env:COMPUTERNAME
hostname
hostnamectl (Linux with systemd)
scutil --get ComputerName (macOS)
System information
systeminfo
systeminfo | findstr /B /C:"OS Name" /C:"OS Version"
Get-ComputerInfo
Get-ComputerInfo | Select OsName,OsVersion,CsTotalPhysicalMemory
Get-CimInstance Win32_OperatingSystem
uname -a
cat /etc/os-release (Linux)
hostnamectl (Linux)
sw_vers (macOS)
Get-ComputerInfo is slow (several seconds). Pick properties with Select-Object.
OS version
ver
[Environment]::OSVersion
$PSVersionTable.PSVersion (PowerShell version)
uname -r (kernel)
lsb_release -a (Debian/Ubuntu)
sw_vers -productVersion (macOS)
CPU
echo %NUMBER_OF_PROCESSORS%
wmic cpu get name,numberofcores (deprecated)
Get-CimInstance Win32_Processor | Select Name,NumberOfCores,NumberOfLogicalProcessors
lscpu (Linux)
nproc (Linux)
sysctl -n machdep.cpu.brand_string (macOS)
Memory
systeminfo | findstr /C:"Total Physical Memory" /C:"Available Physical Memory"
Get-CimInstance Win32_OperatingSystem | Select TotalVisibleMemorySize,FreePhysicalMemory
Get-CimInstance Win32_PhysicalMemory | Select Capacity,Speed
free -h (Linux)
cat /proc/meminfo (Linux)
vm_stat (macOS)
top (any)
Uptime
systeminfo | findstr /C:"System Boot Time"
net statistics workstation | findstr "since"
(Get-Date) - (Get-CimInstance Win32_OperatingSystem).LastBootUpTime
Get-Uptime (PowerShell 6+ only)
uptime
uptime -p (pretty, Linux)
uptime -s (boot time, Linux)
Date and time
date /T
time /T
echo %DATE% %TIME%
Get-Date
Get-Date -Format "yyyy-MM-dd HH:mm:ss"
Get-Date -UFormat "%Y-%m-%d"
date
date +"%Y-%m-%d %H:%M:%S"
date -u (UTC)
Without /T, CMD's date and time commands prompt you to change the clock (πŸ”’ admin).
Logged-in users
query user (alias: quser)
query user
Get-CimInstance Win32_ComputerSystem | Select UserName
who
w (who, plus what they are running)
last (login history)

Processes, Services and Power

TaskCMDPowerShellBashNotes
β˜… List processes
tasklist
tasklist /V (verbose)
tasklist /FI "IMAGENAME eq chrome.exe"
Get-Process (alias: ps, gps)
Get-Process -Name chrome
Get-Process | Sort-Object CPU -Descending | Select -First 10
ps aux
ps aux | grep nginx
top (live)
htop (live, nicer; needs install)
β˜… Kill process
taskkill /IM notepad.exe
taskkill /PID 1234 /F (force)
taskkill /F /IM chrome.exe /T (with child processes)
Stop-Process -Name notepad (alias: kill)
Stop-Process -Id 1234 -Force
kill 1234 (SIGTERM, polite)
kill -9 1234 (SIGKILL, force)
pkill -f pattern
killall firefox
⚠ Force-killing skips cleanup and can corrupt files being written. Try the polite form first.
Find process using a port
netstat -ano | findstr :8080 (PID in last column)
Get-NetTCPConnection -LocalPort 8080 | Select OwningProcess
Get-Process -Id (Get-NetTCPConnection -LocalPort 8080).OwningProcess
sudo lsof -i :8080
sudo ss -ltnp | grep 8080 (Linux)
Run in background
start /B program.exe (same window)
start "" notepad.exe (new window)
Start-Process notepad
Start-Job { long-task }; Get-Job; Receive-Job 1
command & (PowerShell 6+)
command &
nohup command & (survives logout)
jobs / fg / bg
Ctrl+Z (suspend the foreground job)
List services
sc query (running)
sc query state= all
net start (running only)
Get-Service
Get-Service | Where Status -eq Running
Get-Service -Name Spooler
systemctl list-units --type=service (Linux)
systemctl list-units --type=service --state=running
launchctl list (macOS)
Start / stop / restart service
sc start Spooler
sc stop Spooler
net stop Spooler && net start Spooler
(net start/stop also work)
Start-Service Spooler
Stop-Service Spooler
Restart-Service Spooler
sudo systemctl start nginx
sudo systemctl stop nginx
sudo systemctl restart nginx
sudo systemctl enable nginx (start at boot)
πŸ”’ Requires admin or sudo. sc and Get-Service use the service name (Spooler), not the display name (Print Spooler).
Service status
sc query Spooler
sc qc Spooler (configuration)
Get-Service Spooler
(Get-Service Spooler).Status
systemctl status nginx
systemctl is-active nginx
journalctl -u nginx -f (follow logs, Linux)
Scheduled tasks
schtasks /query
schtasks /create /tn Backup /tr C:\backup.bat /sc daily /st 02:00
schtasks /delete /tn Backup
Get-ScheduledTask
Get-ScheduledTask Backup | Start-ScheduledTask
Register-ScheduledTask (see the Get-Help examples)
crontab -l (list)
crontab -e (edit)
0 2 * * * /path/backup.sh (daily at 02:00)
launchctl (macOS launchd)
Restart system
shutdown /r /t 0
shutdown /a (abort a pending shutdown)
Restart-Computer
Restart-Computer -Force
sudo reboot
sudo shutdown -r now
sudo shutdown -r +5 (in 5 minutes)
πŸ”’ Requires admin or sudo.
Shut down system
shutdown /s /t 0
shutdown /s /t 60 (in 60 seconds)
shutdown /h (hibernate)
Stop-Computer
Stop-Computer -Force
sudo shutdown -h now
sudo poweroff
sudo shutdown -c (cancel, Linux)
πŸ”’ Requires admin or sudo.

Networking and Diagnostics

TaskCMDPowerShellBashNotes
β˜… Ping host
ping google.com (4 packets)
ping -n 10 192.168.1.1
ping -t host (until Ctrl+C)
Test-Connection google.com
Test-Connection 8.8.8.8 -Count 5
Test-Connection host -Quiet (True/False)
ping google.com (until Ctrl+C)
ping -c 5 google.com
Windows ping stops after 4 packets by default. Unix ping runs until you stop it.
β˜… IP configuration
ipconfig
ipconfig /all (MAC, DNS, DHCP)
ipconfig /release && ipconfig /renew
Get-NetIPConfiguration
Get-NetIPAddress -AddressFamily IPv4
ip addr (Linux; short form: ip a)
ifconfig (macOS; deprecated on Linux)
hostname -I (Linux, addresses only)
Public IP
curl ifconfig.me
Invoke-RestMethod ifconfig.me
curl ifconfig.me
Connections and open ports
netstat -an (all)
netstat -ano (with PIDs)
netstat -b (with program names, πŸ”’ admin)
Get-NetTCPConnection
Get-NetTCPConnection -State Listen
ss -tulpn (Linux, preferred)
sudo netstat -tulpn (older Linux)
sudo lsof -i -P (macOS and Linux)
netstat and ifconfig are deprecated on Linux in favour of ss and ip, but still work on macOS.
DNS lookup
nslookup google.com
nslookup google.com 8.8.8.8 (ask a specific server)
nslookup -type=MX google.com
Resolve-DnsName google.com
Resolve-DnsName google.com -Type MX
Resolve-DnsName google.com -Server 8.8.8.8
dig google.com
dig +short google.com
dig MX google.com
host google.com
Trace route
tracert google.com
tracert -d google.com (skip DNS, faster)
pathping google.com
Test-NetConnection google.com -TraceRoute
traceroute google.com
tracepath google.com (Linux, no root needed)
mtr google.com (live; needs install)
Routing table
route print
route add 192.168.2.0 mask 255.255.255.0 192.168.1.1
Get-NetRoute
New-NetRoute -DestinationPrefix 192.168.2.0/24 -NextHop 192.168.1.1 -InterfaceIndex 12
ip route (Linux)
sudo ip route add 192.168.2.0/24 via 192.168.1.1
netstat -rn (macOS)
πŸ”’ Adding routes needs admin or sudo.
Flush DNS cache
ipconfig /flushdns
ipconfig /displaydns
Clear-DnsClientCache
Get-DnsClientCache
sudo resolvectl flush-caches (Linux, systemd-resolved)
sudo dscacheutil -flushcache; sudo killall -HUP mDNSResponder (macOS)
ARP table
arp -a
Get-NetNeighbor
Get-NetNeighbor -State Reachable
ip neigh (Linux)
arp -a (macOS and Linux)
Download file
curl -O https://example.com/file.zip
curl -L -o out.zip URL (follow redirects, custom name)
certutil -urlcache -split -f URL file.zip (legacy)
Invoke-WebRequest URL -OutFile file.zip (alias: iwr)
Invoke-RestMethod URL (parses JSON) (alias: irm)
curl.exe -O URL
wget URL
curl -O URL
curl -L -o out.zip URL
In Windows PowerShell 5.1, curl is an alias of Invoke-WebRequest. Type curl.exe to get the real tool.
Test a port
curl -v telnet://host:443
telnet host 80 (optional feature, off by default)
Test-NetConnection host -Port 443 (alias: tnc)
tnc host -Port 443 -InformationLevel Quiet
nc -zv host 443
curl -v telnet://host:443
(echo > /dev/tcp/host/443) && echo open (Bash only)
SSH and remote copy
ssh user@host
scp file.txt user@host:/path/
ssh -i key.pem user@host
ssh user@host
scp file.txt user@host:/path/
Enter-PSSession -ComputerName host (WinRM, Windows to Windows)
ssh user@host
scp file.txt user@host:/path/
rsync -avz src/ user@host:/dest/
The OpenSSH client is built into Windows 10 1809 and later.

Environment, History and Shell Basics

TaskCMDPowerShellBashNotes
β˜… Show environment variables
set
set PATH (all starting with PATH)
echo %PATH%
Get-ChildItem Env: (or: dir env:)
$env:PATH
$env:PATH -split ';' (one per line)
printenv
env
echo $PATH
echo $PATH | tr ':' '\n' (one per line)
Set environment variable
set MYVAR=value (this session)
setx MYVAR value (permanent, new windows only)
setx PATH "%PATH%;C:\tools" (⚠ truncates at 1024 chars)
$env:MYVAR = 'value' (this session)
[Environment]::SetEnvironmentVariable('MYVAR','value','User') (permanent)
export MYVAR=value (this session)
MYVAR=value command (one command only)
add the export line to ~/.bashrc or ~/.zshrc (permanent)
Permanent changes only affect shells opened afterwards.
β˜… Command history
doskey /history
F7 (popup list)
Get-History (alias: h, history)
Get-Content (Get-PSReadLineOption).HistorySavePath (all sessions)
history
history 20 (last 20)
history | grep ssh
Re-run a command
F3 or ↑ (previous)
↑ (previous)
Invoke-History 5 (alias: r 5)
!! (previous)
!5 (history entry 5)
!ssh (last command starting with ssh)
sudo !! (repeat with sudo)
Search history
F7 (dialog)
type a prefix, then F8 (cycle matches)
Ctrl+R (reverse search)
type a prefix, then F8
Get-History | Where CommandLine -like '*git*'
Ctrl+R (reverse search)
history | grep pattern
Aliases
doskey ll=dir /B $* (this session)
(persist via a startup script in the AutoRun registry key)
Set-Alias ll Get-ChildItem
Get-Alias (list all)
function gs { git status } (aliases cannot take arguments; use a function)
alias ll='ls -la'
alias (list all)
unalias ll
Shell profile / startup
HKCU\Software\Microsoft\Command Processor\AutoRun (registry value)
$PROFILE (path to your profile script)
notepad $PROFILE
. $PROFILE (reload)
~/.bashrc (interactive Bash)
~/.bash_profile (login shells)
~/.zshrc (zsh; default on macOS)
source ~/.bashrc (reload)
Put aliases, functions and PATH changes in the profile so they survive between sessions.
Exit code of last command
echo %ERRORLEVEL%
if %ERRORLEVEL% neq 0 echo failed
$? (True or False)
$LASTEXITCODE (from the last native .exe)
echo $? (0 means success)
Chain commands
a && b (b only if a succeeds)
a || b (b only if a fails)
a & b (both, regardless)
a; b (both, regardless)
a && b, a || b (PowerShell 7+ only)
(-and / -or are boolean operators, not chaining)
a && b
a || b
a; b
β˜… Get help
dir /?
help copy
Get-Help Get-Process -Examples
Get-Help *-Service (search by name)
Get-Command -Noun Service
Update-Help (once, πŸ”’ admin)
man ls
ls --help
tldr ls (needs install)
Run as admin / root
runas /user:Administrator cmd
(or right-click the shell and choose Run as administrator)
Start-Process powershell -Verb RunAs
sudo command (Windows 11 24H2+; enable in Settings > System > For developers)
sudo command
sudo -i (root shell)
su - (switch user)

Text Processing and Output

TaskCMDPowerShellBashNotes
Display text
echo Hello World
echo %PATH%
echo. (blank line)
Write-Output 'Hello' (alias: echo, write)
Write-Host 'Text' -ForegroundColor Red (console only, not pipeable)
"Value: $var" (double quotes expand variables)
echo "Hello World"
printf "%s\n" "text"
echo -e "a\tb" (interpret escapes)
View a page at a time
more file.txt
dir /S | more
Get-Content file.txt | more
Get-Content file.txt | Out-Host -Paging
less file.txt (q quits, / searches)
more file.txt
cat file.txt | less
First lines of a file
more +5 file.txt (skip the first 5 instead)
(none; use PowerShell)
Get-Content file.txt -Head 10
Get-Content file.txt | Select-Object -First 10
head file.txt (10 lines)
head -n 20 file.txt
head -c 100 file.bin (bytes)
Last lines of a file
(none; use PowerShell)
Get-Content file.txt -Tail 10
Get-Content log.txt -Wait (follow, like tail -f)
tail file.txt
tail -n 20 file.txt
tail -f log.txt (follow)
Count lines / words
find /c /v "" < file.txt (lines)
type file.txt | find /c "error" (matching lines)
Get-Content file.txt | Measure-Object -Line -Word -Character
(Get-Content file.txt).Count (lines)
wc -l file.txt (lines)
wc -w file.txt (words)
grep -c error file.txt (matching lines)
Sort lines
sort file.txt
sort /R file.txt (reverse)
dir /B | sort
Get-Content file.txt | Sort-Object
Sort-Object -Unique
Get-Process | Sort-Object CPU -Descending
sort file.txt
sort -r (reverse), -n (numeric), -u (unique)
sort -k2 file.txt (by second field)
Unique lines
(none; use PowerShell)
Get-Content file.txt | Sort-Object -Unique
Get-Content file.txt | Group-Object | Sort Count -Desc (with counts)
sort -u file.txt
sort file.txt | uniq -c (with counts)
uniq file.txt (adjacent duplicates only)
Filter a stream
dir | find "txt"
tasklist | findstr /I chrome
Get-Process | Where-Object Name -like 'chrome*' (alias: where, ?)
Get-Process | Where CPU -gt 100
gc log.txt | sls error
ps aux | grep chrome
grep -v debug log.txt (invert match)
PowerShell pipes objects, not text: filter on properties with Where-Object, then shape output with Select-Object or Format-Table.
Find and replace
(none; use PowerShell)
(Get-Content file.txt) -replace 'old','new' | Set-Content file.txt
'text' -replace '(\d+)','[$1]' (regex by default)
sed 's/old/new/g' file.txt (prints result)
sed -i 's/old/new/g' file.txt (in place, Linux)
sed -i '' 's/old/new/g' file.txt (in place, macOS)
The parentheses around Get-Content read the whole file first so PowerShell can safely overwrite it.
Extract columns / fields
for /f "tokens=2 delims=," %i in (file.csv) do @echo %i
(inside a .bat file use %%i)
Import-Csv data.csv | Select-Object Name,Email
'a,b,c' -split ','
Get-Content f.txt | ForEach { ($_ -split '\s+')[1] }
cut -d, -f2 file.csv
awk '{print $2}' file.txt
awk -F: '{print $1}' /etc/passwd
Shape and export output
dir /B /O-D (bare, newest first)
tasklist /FO CSV
tasklist /FO CSV > procs.csv
Get-Process | Select-Object Name,CPU
Get-Process | Format-Table -AutoSize
Get-Process | Format-List *
Get-Process | Export-Csv procs.csv -NoTypeInformation
Get-Process | ConvertTo-Json
Get-Service | Out-GridView
column -t file.txt (align columns)
ls -l | awk '{print $9, $5}'
jq . file.json (needs install)
Format-* cmdlets must be last in a pipeline; their output is for the screen only.
Clipboard
dir | clip
Get-Process | Set-Clipboard (alias: scb)
Get-Clipboard (alias: gcb)
ls | clip
ls | pbcopy (macOS), pbpaste
ls | xclip -selection clipboard (Linux, X11)
ls | wl-copy (Linux, Wayland)

Redirection and Piping

TaskCMDPowerShellBashNotes
Redirect output (overwrite) >
dir > list.txt
Get-Process > processes.txt
Get-Process | Out-File -Encoding utf8 p.txt
Get-Process | Set-Content p.txt
ls -la > listing.txt
Windows PowerShell 5.1 writes UTF-16 with >. Use Out-File -Encoding utf8 for files other tools will read. PowerShell 7 defaults to UTF-8.
Redirect output (append) >>
echo text >> file.txt
Get-Date >> log.txt
Add-Content log.txt 'line'
echo "new line" >> file.txt
Redirect input <
sort < unsorted.txt
Get-Content input.txt | Sort-Object
(PowerShell has no < operator)
sort < unsorted.txt
cat <<EOF ... EOF (here-document)
cmd <<< "string" (here-string)
Pipe |
dir | find "txt"
type file.txt | more
Get-Process | Sort-Object CPU -Descending | Select -First 5
Get-ChildItem | Where Length -gt 1MB
ls -la | grep txt
cat file.txt | sort | uniq -c
CMD and Bash pipe text. PowerShell pipes objects; $_ (or $PSItem) is the current object inside a script block.
Redirect errors 2>
command 2> errors.txt
command 2>&1 (merge errors into output)
command 2> errors.txt
command 2>&1
$ErrorActionPreference = 'Stop' (make errors terminate)
command 2> errors.txt
command 2>&1
Redirect everything
command > out.txt 2>&1
command *> all.txt
command 3>&1 (warnings), 4>&1 (verbose), 6>&1 (information)
command &> out.txt
command > out.txt 2>&1
Suppress output
command > nul
command > nul 2>&1
command | Out-Null
command > $null
$null = command (fastest)
command > /dev/null
command &> /dev/null
command 2> /dev/null (errors only)
Tee (file and screen)
(none; use PowerShell)
Get-Process | Tee-Object -FilePath p.txt
Get-Process | Tee-Object -Variable procs | Select Name
ls | tee listing.txt
ls | tee -a listing.txt (append)
echo x | sudo tee /etc/file (write as root)
Command substitution
for /f %i in ('date /T') do set today=%i
$today = Get-Date -Format yyyy-MM-dd
Write-Output "Today: $(Get-Date)"
Copy-Item a.txt "backup-$(Get-Date -f yyyyMMdd).txt"
today=$(date +%F)
echo "Today: $(date)"
cp a.txt "backup-$(date +%F).txt"

Users and Groups

TaskCMDPowerShellBashNotes
List users
net user
net user alice (details)
Get-LocalUser
Get-LocalUser | Where Enabled
cat /etc/passwd (Linux)
getent passwd
dscl . list /Users (macOS)
Add user
net user alice * /add (prompts for password)
New-LocalUser alice -Password (Read-Host -AsSecureString)
New-LocalUser alice -NoPassword
sudo adduser alice (interactive, Debian/Ubuntu)
sudo useradd -m alice && sudo passwd alice
πŸ”’ Requires admin or sudo. Avoid typing passwords on the command line: they end up in history.
Delete user
net user alice /delete
Remove-LocalUser alice
sudo userdel alice
sudo userdel -r alice (also remove home dir)
πŸ”’ Requires admin or sudo.
Change password
net user alice * (prompts)
Set-LocalUser alice -Password (Read-Host -AsSecureString)
passwd (your own)
sudo passwd alice
List groups
net localgroup
net localgroup Administrators (members)
Get-LocalGroup
Get-LocalGroupMember Administrators
groups (current user)
getent group
id alice
Add user to group
net localgroup Administrators alice /add
Add-LocalGroupMember -Group Administrators -Member alice
sudo usermod -aG sudo alice (Debian/Ubuntu)
sudo usermod -aG wheel alice (Fedora/RHEL)
(log out and back in to apply)
πŸ”’ Requires admin or sudo. ⚠ Forgetting -a in usermod removes the user from all other groups.

Package Management

TaskCMDPowerShellBashNotes
List installed
winget list
winget list
choco list (Chocolatey)
Get-Module -ListAvailable (PowerShell modules)
apt list --installed (Debian/Ubuntu)
dnf list installed (Fedora/RHEL)
brew list (macOS)
pacman -Q (Arch)
wmic product get name is deprecated and very slow; use winget instead.
Search
winget search vscode
winget search vscode
choco search vscode
Find-Module PSReadLine
apt search vscode
dnf search vscode
brew search vscode
Show package info
winget show Git.Git
winget show Git.Git
apt show git
dnf info git
brew info git
Install
winget install Git.Git
winget install --id Git.Git -e (exact id)
winget install Git.Git
choco install git -y
Install-Module PSReadLine (PowerShell module)
sudo apt install git
sudo dnf install git
brew install git
sudo pacman -S git
πŸ”’ Usually needs admin or sudo. brew and per-user winget installs are the exception.
Update
winget upgrade (list available)
winget upgrade --all
winget upgrade --all
choco upgrade all
Update-Module
sudo apt update && sudo apt upgrade
sudo dnf upgrade
brew update && brew upgrade
sudo pacman -Syu
apt update only refreshes the package index. apt upgrade does the installing.
Remove
winget uninstall Git.Git
winget uninstall Git.Git
choco uninstall git
Uninstall-Module name
sudo apt remove git (keeps config)
sudo apt purge git (removes config)
sudo apt autoremove (orphaned dependencies)
brew uninstall git

Developer Setup

TaskWindowsmacOSLinuxNotes
Install WSL (Linux on Windows)
wsl --install (Ubuntu by default; reboot afterwards)
wsl --install -d Debian (pick a distro)
wsl -l -v (list distros and versions)
wsl --update
wsl --shutdown
wsl (open the default distro)
(not needed; macOS is already Unix)
(not needed)
πŸ”’ Run from an administrator prompt. Inside WSL, Windows drives are under /mnt/c and Windows tools are on the PATH, so code . opens VS Code.
Package manager
winget --version (built in on Windows 10 1709+ and 11)
winget source update
(Chocolatey is optional: see chocolatey.org/install)
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
brew doctor
(apt, dnf or pacman is already installed)
sudo apt update (refresh the index first)
If winget is missing, install "App Installer" from the Microsoft Store.
Git
winget install --id Git.Git -e
git --version
xcode-select --install (Apple's git plus compilers)
brew install git (newer version)
sudo apt install git
sudo dnf install git
On Windows this also installs Git Bash.
GitHub CLI
winget install --id GitHub.cli -e
gh auth login
brew install gh
gh auth login
sudo apt install gh (Ubuntu 23.04+; older distros: see cli.github.com)
gh auth login
gh auth login signs in through the browser and stores credentials that git push uses too.
SSH key for GitHub
ssh-keygen -t ed25519 -C "you@example.com"
Get-Service ssh-agent | Set-Service -StartupType Automatic; Start-Service ssh-agent (PowerShell, πŸ”’ admin)
ssh-add $env:USERPROFILE\.ssh\id_ed25519 (PowerShell)
gh ssh-key add ~/.ssh/id_ed25519.pub
ssh-keygen -t ed25519 -C "you@example.com"
ssh-add --apple-use-keychain ~/.ssh/id_ed25519
gh ssh-key add ~/.ssh/id_ed25519.pub
ssh-keygen -t ed25519 -C "you@example.com"
eval "$(ssh-agent -s)"; ssh-add ~/.ssh/id_ed25519
gh ssh-key add ~/.ssh/id_ed25519.pub
Test with ssh -T git@github.com. The Windows ssh-agent service is off by default.
Node.js
winget install OpenJS.NodeJS.LTS
winget install Schniz.fnm (version manager)
node -v; npm -v
brew install node
brew install fnm (version manager)
curl -fsSL https://fnm.vercel.app/install | bash (version manager)
fnm install --lts
(distro packages are often years old)
A version manager such as fnm or nvm lets you switch Node versions per project.
Python
winget install Python.Python.3.12
python --version
py -3 (launcher; picks an installed version)
brew install python
python3 --version
sudo apt install python3 python3-pip python3-venv
python3 --version
Per-project environment: python -m venv .venv, then .venv\Scripts\activate (Windows) or source .venv/bin/activate.
VS Code
winget install Microsoft.VisualStudioCode
code . (open the current folder)
brew install --cask visual-studio-code
code . (first run Shell Command: Install code from the Command Palette)
sudo snap install code --classic
(or the .deb / .rpm from code.visualstudio.com)
code .
PowerShell 7 and Windows Terminal
winget install Microsoft.PowerShell
winget install Microsoft.WindowsTerminal
pwsh (start PowerShell 7)
brew install --cask powershell
pwsh
(see Microsoft's install page for your distro)
pwsh
Windows PowerShell 5.1 is built in. PowerShell 7 (pwsh) is the current cross-platform version and installs alongside it. Windows 11 already includes Windows Terminal.
Compilers and build tools
winget install Microsoft.VisualStudio.2022.BuildTools
(choose "Desktop development with C++" in the installer)
xcode-select --install
sudo apt install build-essential
sudo dnf groupinstall "Development Tools"
Needed by npm and pip packages that compile native code.
Docker
winget install Docker.DockerDesktop
docker run hello-world
brew install --cask docker
docker run hello-world
curl -fsSL https://get.docker.com | sh
sudo usermod -aG docker $USER (then log out and in)
docker run hello-world
Docker Desktop on Windows runs on WSL 2, so install WSL first.
Allow PowerShell scripts
Set-ExecutionPolicy RemoteSigned -Scope CurrentUser (PowerShell)
Get-ExecutionPolicy -List
(not needed)
(not needed)
Fixes "running scripts is disabled on this system". RemoteSigned runs local scripts and signed downloads only.
Check what is installed
winget list
git --version; node -v; python --version; code -v
where git (path to the executable)
brew list
git --version; node -v; python3 --version
which git
apt list --installed 2>/dev/null | grep -i git
git --version; node -v; python3 --version
which git
After installing anything, open a new terminal window. Existing shells keep the old PATH.

Git

TaskCommandNotes
One-time setup
git config --global user.name "Your Name"
git config --global user.email "you@example.com"
git config --global init.defaultBranch main
git config --list (show all settings)
Settings live in ~/.gitconfig. Drop --global to set them for one repository only.
Start a repository
git init
git clone https://github.com/user/repo.git
git clone --depth 1 URL (latest commit only, fast)
See what changed
git status
git status -s (short form)
git diff (unstaged changes)
git diff --staged (what will be committed)
git diff main..feature (between branches)
History
git log --oneline --graph --all
git log -p file.txt (changes to one file)
git log -5 --stat
git show HEAD (last commit in full)
git blame file.txt (who changed each line)
Stage and commit
git add file.txt
git add -A (everything)
git add -p (pick hunks interactively)
git commit -m "Message"
git commit -am "Message" (add tracked files and commit)
git commit --amend (fix the last commit)
⚠ Do not amend a commit you have already pushed; it rewrites history others may have.
Unstage or discard
git restore --staged file.txt (unstage, keep changes)
git restore file.txt (discard local changes)
git clean -fd (delete untracked files and folders)
git clean -n (dry run first)
⚠ restore and clean throw work away with no undo. Run git clean -n first.
Branches
git branch (list)
git branch -a (include remote)
git switch -c feature (create and switch)
git switch main
git branch -m old new (rename)
git branch -d feature (delete merged)
git branch -D feature (force delete)
switch and restore replaced the overloaded checkout in Git 2.23. checkout still works everywhere.
Merge and rebase
git merge feature (merge into current branch)
git rebase main (replay current branch onto main)
git rebase -i HEAD~3 (squash or reorder last 3)
git merge --abort / git rebase --abort
Merge keeps history as it happened. Rebase makes it linear. ⚠ Never rebase commits that are already pushed and shared.
Remotes
git remote -v
git remote add origin https://github.com/user/repo.git
git remote set-url origin NEW_URL
Push and pull
git push -u origin main (first push; sets upstream)
git push
git pull (fetch and merge)
git pull --rebase
git fetch (download without merging)
git push origin --delete feature (delete remote branch)
Undo commits
git revert HEAD (new commit that undoes the last one; safe)
git reset --soft HEAD~1 (uncommit, keep changes staged)
git reset --mixed HEAD~1 (uncommit, keep changes unstaged)
git reset --hard HEAD~1 (uncommit and discard changes)
git reflog (find lost commits)
⚠ reset --hard deletes work. revert is the safe choice for anything already pushed. reflog can recover a reset for about 30 days.
Stash
git stash (shelve changes)
git stash push -m "wip" (with a name)
git stash list
git stash pop (restore latest and drop it)
git stash apply stash@{1}
git stash drop
Tags and releases
git tag (list)
git tag -a v1.0 -m "Release 1.0"
git push --tags
git checkout v1.0 (look at a tag)
Ignore and untrack files
git rm --cached file.txt (stop tracking, keep file)
git rm -r --cached folder/
git check-ignore -v file.txt (why is this ignored?)
git mv old.txt new.txt (rename and stage)
Patterns in .gitignore only affect files not yet tracked. Untrack committed files with git rm --cached first.
Search
git grep "pattern" (search tracked files)
git log -S "text" (commits that added or removed text)
git log --grep "fix" (search commit messages)
git log --author="Name"
Who did what
git shortlog -sn (commits per author)
git log --since="2 weeks ago"
git bisect start / git bisect good v1.0 / git bisect bad (find the breaking commit)
Help
git help commit
git commit -h (short flag list)
git <command> --help

Keyboard Shortcuts

ActionCMDPowerShellBashNotes
Auto-complete
Tab
Tab (Ctrl+Space shows a menu)
Tab (press twice to list options)
Previous / next command
↑ / ↓ (F3 repeats the last one)
↑ / ↓
↑ / ↓ or Ctrl+P / Ctrl+N
Search history
F7 (list), F8 (cycle prefix matches)
Ctrl+R (backward), Ctrl+S (forward), F8
Ctrl+R (backward), Ctrl+S (forward)
Clear screen
cls (no shortcut)
Ctrl+L
Ctrl+L
Cancel running command
Ctrl+C
Ctrl+C
Ctrl+C
Clear current line
Esc
Esc
Ctrl+U (before cursor), Ctrl+K (after cursor)
In PowerShell, Ctrl+U and Ctrl+K also work with the default key mode.
Start / end of line
Home / End
Home / End (also Ctrl+A / Ctrl+E)
Ctrl+A / Ctrl+E (Home / End in most terminals)
Move by word
Ctrl+← / Ctrl+β†’
Ctrl+← / Ctrl+β†’
Alt+B / Alt+F (Ctrl+← / β†’ in many terminals)
Delete word before cursor
(none)
Ctrl+Backspace
Ctrl+W
Delete word after cursor
(none)
Ctrl+Delete
Alt+D
Undo an edit
(none)
Ctrl+Z
Ctrl+_ or Ctrl+X Ctrl+U
Paste
Ctrl+V or right-click
Ctrl+V or right-click
Ctrl+Shift+V (Cmd+V on macOS)
Copy and paste are handled by the terminal app, not the shell. In Bash Ctrl+C cancels and Ctrl+V inserts a literal key.
Copy
Select, then Enter or Ctrl+C
Select, then Enter or Ctrl+C
Ctrl+Shift+C (Cmd+C on macOS)
Pause / resume output
Ctrl+S / Ctrl+Q
Ctrl+S / Ctrl+Q
Ctrl+S / Ctrl+Q
If the terminal seems frozen, you probably hit Ctrl+S. Press Ctrl+Q.
Suspend foreground job
(none)
(none)
Ctrl+Z (resume with fg or bg)
Exit shell
exit
exit (Ctrl+D on an empty line)
exit or Ctrl+D
In CMD, Ctrl+Z is the end-of-file character, not exit.

Notes and Gotchas

Paths

  • Windows uses backslashes (C:\Users\Alice). Bash uses forward slashes (/home/alice). PowerShell accepts both.
  • Quote any path containing spaces: "C:\Program Files" or '/My Files'.
  • Windows file systems are case-insensitive. Linux is case-sensitive: File.txt and file.txt are different files. macOS is case-insensitive by default.

Quoting and escaping

  • CMD: escape special characters (& < > | ^) with a caret: echo a ^& b. Variables are %NAME%.
  • PowerShell: single quotes are literal, double quotes expand $variables and $(expressions). The escape character is the backtick (`).
  • Bash: single quotes are literal, double quotes expand $variables and $(commands). The escape character is the backslash (\).

Wildcards

  • * matches any number of characters (*.txt). ? matches exactly one character (file?.txt).
  • [abc] and [a-z] match one character from a set (Bash and PowerShell, not CMD).
  • In Bash the shell expands wildcards before the command runs. Quote them ("*.txt") when the command should see the pattern itself, as with find and grep.

PowerShell is different

  • Commands are Verb-Noun cmdlets (Get-Process, Stop-Service). Aliases such as ls, cat, rm and ps map to cmdlets, but their flags are PowerShell flags: ls -Force, not ls -a.
  • Pipelines carry objects, not text. Filter with Where-Object, pick columns with Select-Object, sort with Sort-Object, and format last.
  • Windows PowerShell 5.1 ships with Windows. PowerShell 7 (pwsh) is a separate install with && and ||, UTF-8 defaults and Get-Uptime.

macOS, zsh and WSL

  • macOS uses zsh as its default shell. Nearly everything in the Bash column works unchanged; profile files are ~/.zshrc instead of ~/.bashrc.
  • macOS ships BSD versions of many tools, so some Linux flags differ (sed -i, ls --color, du --max-depth). Commands marked (Linux) do not exist on macOS and vice versa.
  • Windows Subsystem for Linux (wsl) gives you a real Linux shell on Windows. Windows drives appear under /mnt/c.

Setting up Windows for development

  • Turn on Developer Mode (Settings > System > For developers). It lets you create symlinks without an admin prompt and, on Windows 11 24H2+, enables the built-in sudo.
  • Long paths: node_modules trees often exceed the 260-character limit. Run git config --global core.longpaths true, and enable "Enable Win32 long paths" in Group Policy or set LongPathsEnabled=1 under HKLM\SYSTEM\CurrentControlSet\Control\FileSystem (πŸ”’ admin).
  • winget installs per user by default; add --scope machine (πŸ”’ admin) to install for everyone.
  • Most installers add themselves to the PATH, but only new terminal windows see it. If a command is "not recognized" right after installing, open a new window first.

Git on Windows

  • Git for Windows installs Git Bash, a Bash shell where the whole Bash column of this sheet works. Git itself works identically in CMD and PowerShell.
  • Line endings: set git config --global core.autocrlf true on Windows (or add a .gitattributes with * text=auto to the repo) so files do not flip between CRLF and LF.
  • Credentials: Git for Windows includes Git Credential Manager, which opens a browser sign-in on the first push and remembers it. On macOS the keychain does the same; on Linux use git config --global credential.helper store or the GitHub CLI (gh auth login).
  • Lots of "modified" files right after a clone with no real changes usually means a line-ending or file-mode mismatch: git config core.fileMode false and check core.autocrlf.