Navigation & Files
pwdPrint current working directorycd /path/to/dirChange directorycd -Go to previous directorycd ~Go to home directoryls -laList files including hidden, long formatls -lhList files with human-readable sizesmkdir -p a/b/cCreate nested directoriesrm -rf dir/Remove directory and contents recursivelycp -r src/ dest/Copy directory recursivelymv old newMove or rename file/directoryln -s target linkCreate symbolic linkfind . -name "*.log"Find files by namefind . -type f -mtime -7Find files modified in last 7 daysfind . -type f -size +10MFind files larger than 10 MBtouch file.txtCreate empty file or update timestampstat file.txtShow file metadata (size, permissions, timestamps)file image.pngDetect file typedu -sh dir/Disk usage of directory, human-readabledf -hDisk free space on all mountschmod 755 script.shSet rwxr-xr-x permissionschmod +x script.shMake file executablechown user:group fileChange file owner and groupText Processing
cat file.txtPrint file contentsless file.txtPage through file (q to quit)head -n 20 file.txtPrint first 20 linestail -n 20 file.txtPrint last 20 linestail -f file.logFollow file as it growsgrep "pattern" file.txtSearch for pattern in filegrep -r "pattern" dir/Recursive search in directorygrep -i "pattern" fileCase-insensitive searchgrep -v "pattern" fileInvert match - show lines NOT matchinggrep -n "pattern" fileShow line numbers with matchesgrep -c "pattern" fileCount matching linessed "s/old/new/g" fileReplace all occurrences in outputsed -i "s/old/new/g" fileReplace in file in-placeawk "{print $1}" filePrint first field of each lineawk -F: "{print $1}" /etc/passwdSet field separator to :cut -d: -f1 /etc/passwdCut field 1 with : delimitersort file.txtSort lines alphabeticallysort -n -k2 file.txtSort numerically by second fieldsort -rn file.txtSort numerically, descendinguniq file.txtRemove consecutive duplicate linessort file.txt | uniq -cCount occurrences of each unique linewc -l file.txtCount lineswc -w file.txtCount wordstr "a-z" "A-Z"Translate characters (stdin)xargs rmPass stdin lines as arguments to commandtee output.txtWrite stdin to file AND stdoutVariables & Expansion
name="Alice"Assign variable - no spaces around =echo "$name"Expand variable (double quotes preserve spaces)echo "${name}"Explicit variable boundary - preferred in stringsecho "${name:-default}"Use default if name is unset or emptyecho "${name:=default}"Assign default if name is unset or emptyecho "${#name}"Length of variable valueecho "${name:2:5}"Substring: offset 2, length 5echo "${name/old/new}"Replace first occurrence in valueecho "${name//old/new}"Replace all occurrences in valueecho "${name^^}"Uppercase all charactersecho "${name,,}"Lowercase all charactersreadonly PI=3.14Declare read-only variableexport VAR=valueExport variable to child processesunset nameRemove variableresult=$(command)Command substitution - capture outputresult=$((3 + 4))Arithmetic expansionecho {a,b,c}.txtBrace expansion: a.txt b.txt c.txtecho {1..5}Brace sequence: 1 2 3 4 5$0, $1, $2Script name, first arg, second arg$#Number of arguments"$@"All arguments as separate words"$*"All arguments as single string$?Exit status of last command$$PID of current shell$!PID of last background processdeclare -i num=5Declare integer variabledeclare -a arr=(1 2 3)Declare indexed arraydeclare -A map=([key]=val)Declare associative arrayArrays
arr=(one two three)Create indexed arrayarr[0]="one"Assign element by indexecho "${arr[0]}"Access element at index 0echo "${arr[@]}"All elementsecho "${#arr[@]}"Array lengtharr+=("four")Append elementunset arr[1]Remove element at index 1echo "${arr[@]:1:2}"Slice: 2 elements starting at index 1for item in "${arr[@]}"; doIterate over array elementsdeclare -A mapDeclare associative array (hash map)map[key]="value"Assign associative array entryecho "${map[key]}"Access associative array entryecho "${!map[@]}"All keys of associative arrayecho "${map[@]}"All values of associative arrayControl Flow
if [ "$x" -eq 1 ]; then ... fiif statementif [[ "$s" == "hi" ]]; then[[ ]] - preferred: handles regex, no word splittingif [[ -z "$s" ]]; then-z true if string is emptyif [[ -n "$s" ]]; then-n true if string is non-emptyif [[ "$a" == "$b" ]]; thenString equalityif [[ "$n" -gt 5 ]]; then-gt -lt -ge -le -eq -ne for integersif [[ -f file ]]; then-f true if file exists and is regular fileif [[ -d dir ]]; then-d true if directory existsif [[ -e path ]]; then-e true if path exists (any type)if [[ -r file ]]; then-r -w -x: readable, writable, executableif cmd; then ... else ... fiBranch on command exit statuscmd1 && cmd2Run cmd2 only if cmd1 succeedscmd1 || cmd2Run cmd2 only if cmd1 failsfor i in 1 2 3; do echo $i; donefor loop over listfor i in {1..10}; dofor loop over rangefor ((i=0; i<5; i++)); doC-style for loopwhile [[ $n -gt 0 ]]; dowhile loopuntil [[ $n -eq 0 ]]; dountil loop - runs while condition is falsebreak / continueExit loop / skip to next iterationcase "$var" in foo) ;; bar) ;; *) ;; esaccase statement - pattern matchingselect opt in a b c; do ... doneInteractive menu (sets $REPLY)Functions
greet() { echo "Hello $1"; }Define functionfunction greet { echo "Hello $1"; }Alternate definition syntaxgreet "Alice"Call function with argumentlocal name="Alice"Local variable - scoped to functionreturn 0Return exit code (0 = success, 1+ = error)result=$(my_func)Capture function output via command substitutionmy_func "$@"Forward all script arguments to functiontype greetCheck if name is function, builtin, or commandunset -f greetRemove function definitionRedirection & Pipes
cmd > fileRedirect stdout to file (overwrite)cmd >> fileRedirect stdout to file (append)cmd < fileRead stdin from filecmd 2> err.logRedirect stderr to filecmd 2>&1Redirect stderr to same destination as stdoutcmd > out.log 2>&1Redirect both stdout and stderr to filecmd &> fileShorthand: redirect both stdout and stderrcmd > /dev/nullDiscard stdoutcmd1 | cmd2Pipe stdout of cmd1 to stdin of cmd2cmd1 |& cmd2Pipe both stdout and stderr to cmd2cat <<EOF ... EOFHere-doc: multi-line string as stdincmd <<< 'string'Here-string: pass string as stdinexec 3> file.txtOpen file descriptor 3 for writingecho "hi" >&3Write to file descriptor 3exec 3>&-Close file descriptor 3Process & Job Control
cmd &Run command in backgroundjobsList background jobsfg %1Bring job 1 to foregroundbg %1Resume job 1 in backgroundCtrl+ZSuspend foreground jobCtrl+CSend SIGINT to foreground processkill PIDSend SIGTERM to processkill -9 PIDSend SIGKILL - force terminatekill %1Kill job by job numberpkill nameKill processes by namekillall nameKill all processes with given nameps auxList all running processesps aux | grep phpFind PHP processespgrep nameGet PID(s) by process nametop / htopInteractive process viewerwaitWait for all background jobs to completewait $!Wait for last background processnohup cmd &Run command immune to hangupdisown %1Remove job from shell job tabletrap "cleanup" EXITRun function on shell exittrap "handler" INT TERMHandle SIGINT and SIGTERM signalsArchives & Compression
tar -czf archive.tar.gz dir/Create gzip-compressed archivetar -cjf archive.tar.bz2 dir/Create bzip2-compressed archivetar -cJf archive.tar.xz dir/Create xz-compressed archivetar -czf archive.tar.gz -C /parent dir/Archive relative to parent directorytar -xzf archive.tar.gzExtract gzip archive in current directorytar -xzf archive.tar.gz -C /dest/Extract to specific directorytar -tzf archive.tar.gzList contents without extractingtar -xzf archive.tar.gz file.txtExtract single file from archivetar -czf - dir/ | ssh host "cat > out.tar.gz"Stream archive over SSHgzip file.txtCompress file → file.txt.gz (removes original)gzip -k file.txtCompress and keep originalgzip -d file.txt.gz / gunzip file.txt.gzDecompress .gz filegzip -9 file.txtMaximum compression levelzcat file.txt.gzPrint contents of .gz without extractingzip -r archive.zip dir/Create zip archive recursivelyzip -r archive.zip dir/ -x "*.git*"Zip excluding a patternunzip archive.zipExtract zip archiveunzip archive.zip -d /dest/Extract zip to specific directoryunzip -l archive.zipList zip contents without extractingNetworking & Remote
curl https://example.comFetch URL and print to stdoutcurl -o file.zip https://example.com/file.zipDownload URL to filecurl -O https://example.com/file.zipDownload URL keeping remote filenamecurl -L urlFollow redirectscurl -s urlSilent mode - suppress progresscurl -I urlFetch headers only (HEAD request)curl -X POST -H "Content-Type: application/json" -d '{"key":"val"}' urlPOST JSON datacurl -u user:pass urlHTTP Basic authenticationcurl -H "Authorization: Bearer $TOKEN" urlBearer token headerwget urlDownload URL to current directorywget -q -O - urlFetch URL quietly to stdoutwget -r -np urlRecursive download, no parent dirsssh user@hostConnect to remote hostssh -p 2222 user@hostConnect on non-default portssh -i ~/.ssh/key.pem user@hostConnect with specific identity filessh -L 8080:localhost:80 user@hostLocal port forwardingssh -R 9090:localhost:3000 user@hostRemote port forwardingscp file.txt user@host:/remote/path/Copy file to remote hostscp user@host:/remote/file.txt .Copy file from remote hostscp -r dir/ user@host:/remote/Copy directory recursivelyrsync -avz dir/ user@host:/remote/Sync directory to remote (archive, verbose, compress)rsync -avz --delete dir/ user@host:/remote/Sync and delete files not in sourcersync -avz --exclude="*.log" dir/ dest/Sync excluding patternrsync -n dir/ dest/Dry run - show what would changeping -c 4 hostPing host 4 timesss -tulpnShow listening TCP/UDP ports and processesnetstat -tulpnSame as ss -tulpn (older systems)Scripting Patterns
#!/usr/bin/env bashShebang - portable bash pathset -euo pipefailExit on error, unset var, pipe failureset -xPrint each command before executing (debug)set +xDisable command tracingecho "msg" >&2Write error message to stderrexit 1Exit script with non-zero status[[ "${BASH_SOURCE[0]}" == "$0" ]]True if script is run directly, not sourcedSCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"Absolute path to script directorysource ./lib.sh / . ./lib.shSource a script into current shellmktempCreate a secure temporary filemktemp -dCreate a secure temporary directoryprintf "%-10s %s\n" "$a" "$b"Formatted outputread -p "Name: " nameRead user input into variableread -s -p "Password: " passRead silently (no echo)getopts "ab:c" optParse short flags; : means arg requiredcommand -v gitCheck if command exists (returns path)hash git 2>/dev/nullCheck if command is in PATH