What it is
Bash is the default command-line interpreter (shell) on most Linux and macOS systems, used for executing commands, scripting automation, and interacting with the operating system.
Installation
Bash is pre-installed on most Linux and macOS systems. If you need to install it separately or on a different OS:
Linux (Debian/Ubuntu):
sudo apt update
sudo apt install bash
Linux (Fedora/CentOS/RHEL):
sudo dnf install bash
# or
sudo yum install bash
macOS: Bash is usually pre-installed. If not, or for an updated version, use Homebrew:
brew install bash
After installation, you might need to configure it as your default shell (e.g., by editing /etc/shells and using chsh -s /path/to/bash).
Windows: Via the Windows Subsystem for Linux (WSL):
- Install WSL from the Microsoft Store or via PowerShell:
wsl --install - Open your chosen Linux distribution (e.g., Ubuntu) from the Start Menu. Bash will be available.
Core Concepts
- Shell: An interpreter that takes commands from the user and tells the operating system to execute them. Bash is one such interpreter.
- Prompt: The text displayed by the shell indicating it’s ready to accept commands. It typically shows the username, hostname, and current directory (e.g.,
user@hostname:~/current/dir$). - Command: An instruction given to the shell. It usually consists of a command name, followed by options (flags) and arguments.
- Path: The location of a file or directory in the file system hierarchy.
- Environment Variables: Variables whose values can affect the way running processes behave.
PATH(where to find executables),HOME(user’s home directory),USER(current username) are common examples. - Standard Streams:
- Stdin (0): Standard input, where commands typically read data from (usually the keyboard).
- Stdout (1): Standard output, where commands typically write their results (usually the terminal screen).
- Stderr (2): Standard error, where commands typically write error messages (usually the terminal screen).
- Redirection: Changing where Stdin, Stdout, or Stderr go.
- Piping: Connecting the Stdout of one command to the Stdin of another.
- Wildcards/Globbing: Special characters (
*,?,[]) used to match filenames. - Job Control: Managing background and foreground processes.
- Scripting: Writing a sequence of Bash commands in a file to automate tasks.
Commands / Usage
Navigating the Filesystem
pwdPrint working directory. Shows your current location.pwd # Output: /home/user/projectscd <directory>Change directory. Moves you to a specified directory.cd /var/log cd ../../etc # Go up two levels, then into etc cd ~ # Go to your home directory cd - # Go to the previous directorylsList directory contents. Shows files and subdirectories.ls # Output: file1.txt mydir script.shls -lList in long format. Shows permissions, owner, size, modification date.ls -l # Output: -rw-r--r-- 1 user group 1024 Jan 15 10:30 file1.txtls -aList all files, including hidden ones (starting with.).ls -a # Output: . .. .bashrc file1.txt mydirls -lhList in long format with human-readable sizes (e.g.,1K,23M,2G).ls -lh # Output: -rw-r--r-- 1 user group 1.1K Jan 15 10:30 file1.txt
Managing Files and Directories
mkdir <directory_name>Make directory. Creates a new directory.mkdir new_project mkdir -p project/src/components # Create parent directories if they don't existtouch <file_name>Create empty file or update timestamp. Creates a file if it doesn’t exist, or updates its modification time if it does.touch report.txt touch log_$(date +%Y%m%d).csvcp <source> <destination>Copy files or directories.cp file1.txt file1_backup.txt cp mydir /tmp/mydir_copy cp -r project_a project_b # Copy directories recursively cp -v file.txt /backup/ # Verbose output, show what's being copiedmv <source> <destination>Move or rename files or directories.mv old_name.txt new_name.txt # Rename mv file.txt /data/ # Move to a different directory mv dir1 dir2 # Rename/move directoryrm <file_name>Remove files. Use with caution!rm temp.log rm -i file.txt # Interactive, prompt before removing rm -f *.tmp # Force removal, ignore nonexistent files, no promptsrmdir <directory_name>Remove empty directory.rmdir empty_folderrm -r <directory_name>Remove directories and their contents recursively. EXTREMELY DANGEROUS.rm -r old_project # Deletes the entire project directory and all its contents rm -rf temp_dir # Force recursive removal without prompts
Viewing and Editing Files
cat <file_name>Concatenate and display file content. Good for small files.cat /etc/hosts cat file1.txt file2.txt > combined.txt # Concatenate two files into a new oneless <file_name>View file content interactively. Allows scrolling forward and backward. Pressqto quit.less large_log_file.loghead <file_name>Display the first 10 lines of a file.head data.csv head -n 20 data.csv # Display first 20 linestail <file_name>Display the last 10 lines of a file.tail error.log tail -n 50 error.log # Display last 50 lines tail -f error.log # Follow file, continuously display new lines as they are addednano <file_name>Simple, beginner-friendly text editor.nano config.ymlvim <file_name>orvi <file_name>Powerful, modal text editor. Requires learning its commands (insert mode, normal mode, visual mode).vim script.sh
Searching and Filtering
grep <pattern> <file_name>Search for patterns in files.grep "error" /var/log/syslog grep -i "warning" app.log # Case-insensitive search grep -r "function_name" src/ # Recursive search in directory grep -v "debug" log.txt # Invert match: show lines NOT containing "debug" grep -E "error|warning" logs.txt # Extended regex: match "error" OR "warning" ps aux | grep nginx # Find running nginx processesfind <path> -name <pattern>Find files by name.find . -name "*.log" # Find all files ending in .log in current dir and subdirs find /etc -type f -name "host*" # Find files starting with "host" in /etc find /tmp -mtime +7 -delete # Find and delete files older than 7 days in /tmpfind <path> -type <f|d>Find files (f) or directories (d).find . -type d -name "config" # Find directories named "config"find <path> -mtime <n>Find files modifiedndays ago.+nfor more thanndays,-nfor less thanndays.find /var/log -mtime +30 # Files modified more than 30 days agowc <file_name>Word count. Counts lines, words, and characters.wc report.txt # Output: 15 120 850 report.txt (lines words bytes) wc -l < file.txt # Count only lines
Permissions
-
chmod <mode> <file/directory>Change file mode bits (permissions).chmod 755 script.sh # rwxr-xr-x (owner: rwx, group: r-x, others: r-x) chmod +x script.sh # Add execute permission for owner, group, and others chmod u+w file.txt # Add write permission for the user (owner) chmod go-rwx data.txt # Remove read, write, execute for group and others chmod a+r public_file.txt # Add read permission for all (user, group, others)- Numeric mode:
r=4,w=2,x=1. Sum for each category (user, group, others).755=(4+2+1)(4+0+1)(4+0+1) - Symbolic mode:
u(user),g(group),o(others),a(all).+(add),-(remove),=(set exactly).
- Numeric mode:
-
chown <user>:<group> <file/directory>Change file owner and group. Requires root privileges (sudo).sudo chown www-data:www-data /var/www/html/index.html sudo chown user1:group1 file.txt sudo chown -R user1:group1 project_dir # Recursively change ownership -
chgrp <group> <file/directory>Change file group.chgrp developers report.txt
Process Management
psReport a snapshot of the current processes.ps aux # Show all processes for all users in BSD format ps -ef # Show all processes in System V formattopDisplay dynamic real-time view of running processes. Pressqto quit.tophtopAn interactive process viewer (often needs installation:sudo apt install htop). More user-friendly thantop.htopkill <PID>Send a signal to a process (default signal is TERM - terminate).kill 12345 # Send SIGTERM to process ID 12345 kill -9 12345 # Send SIGKILL (force kill) to process ID 12345 kill -HUP 12345 # Send SIGHUP (hang up), often used to reload configpkill <process_name>Kill processes based on their name.pkill nginx pkill -f "my_long_running_script.py" # Kill process whose command line matches patternpgrep <process_name>Find the process ID (PID) of a process.pgrep sshdbgPut the most recently stopped background job into the background.fgBring the most recently stopped background job to the foreground.jobsList currently running background jobs.Ctrl+ZSuspend the current foreground process (stops it, doesn’t kill it). Can then usebgorfg.
Input/Output Redirection and Piping
>Redirect standard output. Overwrites the file.ls -l > file_listing.txt echo "Hello World" > greeting.txt>>Append standard output to a file.echo "Another line" >> greeting.txt date >> system_log.txt<Redirect standard input from a file.sort < unsorted_list.txt > sorted_list.txt grep "pattern" < input.txt2>Redirect standard error.find / -name "*.conf" 2> find_errors.log # Redirect only errors&>or>&Redirect both standard output and standard error../my_script.sh &> script_output_and_errors.log|(Pipe) Send standard output of the command on the left to the standard input of the command on the right.ls -l | grep ".txt" # List files, then filter for lines containing ".txt" cat access.log | grep "404" | wc -l # Count 404 errors in access log ps aux | sort -k 3 -nr # List processes, sort by CPU usage (descending)2>&1Redirect stderr to stdout. Often used with pipes or redirection to capture both../my_script.sh 2>&1 | tee script_log.txt # Capture stdout and stderr, and also print to terminal ./my_script.sh > output.log 2>&1 # Redirect stdout to file, stderr to stdout (which is redirected to file)
Environment Variables
echo $<VARIABLE_NAME>Display the value of an environment variable.echo $HOME echo $PATH echo $USERexport <VARIABLE_NAME>=<value>Set and export an environment variable, making it available to child processes.export MY_API_KEY="abcdef12345" export PATH="$PATH:/usr/local/bin" # Add a directory to the PATHunset <VARIABLE_NAME>Unset (remove) an environment variable.unset MY_API_KEYenvDisplay all environment variables.printenvPrint all or some environment variables.
Archiving and Compression
tar -cvf archive.tar <file1> <dir1>Create a tar archive (without compression).tar -cvf backup.tar /home/user/documentstar -xvf archive.tarExtract a tar archive.tar -xvf backup.tar -C /mnt/restore_point # Extract to a specific directorytar -czvf archive.tar.gz <file1> <dir1>Create a gzipped tar archive.tar -czvf website_backup.tar.gz /var/www/htmltar -xzvf archive.tar.gzExtract a gzipped tar archive.tar -xzvf website_backup.tar.gztar -cjvf archive.tar.bz2 <file1> <dir1>Create a bzip2 compressed tar archive.tar -cjvf large_archive.tar.bz2 huge_data/tar -xjvf archive.tar.bz2Extract a bzip2 compressed tar archive.tar -xjvf large_archive.tar.bz2gzip <file>Compress a file using gzip (creates.gzfile, removes original).gzip large_log.txt # Creates large_log.txt.gzgunzip <file.gz>Decompress a gzip file.gunzip large_log.txt.gzzip archive.zip <file1> <dir1>Create a zip archive.zip -r project_files.zip src/ config/unzip archive.zipExtract a zip archive.unzip project_files.zip
Networking
ping <host>Send ICMP ECHO_REQUEST packets to network hosts.ping google.com ping -c 4 192.168.1.1 # Send 4 pingscurl <URL>Transfer data from or to a server. Primarily for HTTP/HTTPS.curl https://api.example.com/data curl -O https://example.com/file.zip # Download file and save with original name curl -L https://example.com # Follow redirects curl -X POST -d '{"key":"value"}' https://api.example.com/resource # POST request curl -I https://example.com # Get headers onlywget <URL>Non-interactive network downloader.wget https://example.com/dataset.csv wget -r -np -nH --cut-dirs=1 https://example.com/files/ # Recursive download, no parent dirs, skip host dir, cut dir depthssh <user>@<host>Connect to a remote machine using the Secure Shell protocol.ssh john@server.example.com ssh -p 2222 user@host.com # Connect using a non-standard portscp <source> <user>@<host>:<destination>Securely copy files between hosts.scp local_file.txt user@remote_server:/path/to/destination/ scp user@remote_server:/path/to/remote_file.txt . # Copy from remote to local current dir scp -r local_directory user@remote_server:/path/
Shell Scripting Basics
#!/bin/bashShebang line. Specifies the interpreter for the script. Must be the first line.#!/bin/bash echo "Hello from my script!"variable=valueAssign a value to a variable. No spaces around=.NAME="Alice" COUNT=10echo $variablePrint the value of a variable.echo "Hello, $NAME!"read <variable_name>Read input from stdin into a variable.echo "Enter your name:" read USER_NAME echo "Hello, $USER_NAME"if [ condition ]; then ... fiConditional execution.if [ $count -gt 5 ]; then echo "Count is greater than 5" fi- Common conditions:
-eq(equal),-ne(not equal),-gt(greater than),-ge(greater or equal),-lt(less than),-le(less or equal),-z(string is empty),-n(string is not empty).
- Common conditions:
for item in list; do ... doneLooping construct.for i in {1..5}; do echo "Number: $i" done for file in *.txt; do echo "Processing $file" # process "$file" donewhile condition; do ... doneLoop while a condition is true.counter=0 while [ $counter -lt 3 ]; do echo "Loop iteration $counter" counter=$((counter + 1)) # Arithmetic expansion done$(command)or`command`Command substitution. Executes a command and substitutes its output.CURRENT_DIR=$(pwd) echo "You are in $CURRENT_DIR" files=`ls *.log` echo "Log files found: $files"$((expression))Arithmetic expansion. For integer arithmetic.SUM=$((5 + 3)) echo $SUM # Output: 8
Wildcards (Globbing)
*Matches zero or more characters.ls *.txt # List all files ending in .txt cp data/* /backup/ # Copy all files in data/ to /backup/?Matches exactly one character.ls file?.log # Matches file1.log, fileA.log, but not file10.log[]Matches any single character within the brackets.ls [abc]*.txt # Matches a.txt, b.txt, c.txt, and also abc.txt ls file[0-9].log # Matches file0.log through file9.log ls [!a-z]*.sh # Matches any .sh file NOT starting with a lowercase letter
Other Useful Commands
alias <name>='<command>'Create a shortcut (alias) for a command.alias ll='ls -lh' alias update='sudo apt update && sudo apt upgrade -y'unalias <name>Remove an alias.unalias llhistoryDisplay a list of previously executed commands.history 10 # Show last 10 commands !101 # Re-execute command number 101 from history !! # Re-execute the last commandman <command>Display the manual page for a command.man ls man grepsudo <command>Execute a command as the superuser (root). Requires password.sudo systemctl restart nginxdf -hDisplay disk space usage in human-readable format.df -hdu -sh <directory>Display disk usage of a directory in human-readable format (summary).du -sh /var/loguname -aPrint system information.uname -a # Output: Linux hostname 5.15.0-91-generic #102-Ubuntu SMP Tue Nov 14 13:30:08 UTC 2023 x86_64 x86_64 x86_64 GNU/LinuxclearClear the terminal screen.
Common Patterns
- Finding large files/directories:
# Find top 10 largest files in current directory and subdirectories du -ah . | sort -rh | head -n 10 # Find top 5 largest directories in /var/log du -sh /var/log/* | sort -rh | head -n 5 - Automating log analysis:
# Count occurrences of 'ERROR' in all .log files in /var/log, case-insensitive grep -ri "error" /var/log/*.log | wc -l # Show the last 100 lines of a log file, then follow new entries tail -n 100 -f /var/log/syslog - Quickly downloading a file:
curl -O https://example.com/path/to/file.zip - Checking if a service is running:
pgrep nginx > /dev/null && echo "Nginx is running" || echo "Nginx is NOT running" # or using systemctl (if available) systemctl is-active nginx --quiet && echo "Nginx is active" || echo "Nginx is inactive" - Executing commands remotely:
ssh user@host.com "ls -l /tmp" ssh user@host.com "sudo systemctl restart apache2" - Copying files to/from remote servers:
# Copy local file to remote server scp myconfig.conf user@server.com:/etc/myapp/ # Copy remote file to local machine scp user@server.com:/var/log/app.log . # Copy local directory recursively scp -r ./my_project user@server.com:/home/user/projects/ - Finding processes by name and killing them:
# Find PID of 'bad_process' pgrep bad_process # Kill all processes named 'bad_process' forcefully pkill -9 bad_process - Chaining commands with
&&and||:&&(AND): Execute the next command only if the previous one succeeded (returned exit code 0).||(OR): Execute the next command only if the previous one failed (returned non-zero exit code).# Update package list, then upgrade packages if update was successful sudo apt update && sudo apt upgrade -y # Try to create a directory, if it fails, print an error mkdir /data/new_dir || echo "Failed to create directory /data/new_dir" # Compile code, then run if compilation succeeded gcc main.c -o myapp && ./myapp - Running commands in the background:
Append
&to a command to run it in the background.sleep 60 & # Sleep for 60 seconds in the background ./long_running_script.sh & - Saving command output to a file and displaying it:
./my_script.sh | tee output.log # Both displays on screen AND saves to output.log
Gotchas
- Quoting: Unquoted spaces in filenames or arguments will cause errors or unexpected behavior. Use quotes (
" ") or escape spaces (\).# Incorrect: # cd My Documents/ # Correct: cd "My Documents/" cd My\ Documents/ rm -rfis irreversible: There is no "undelete" command. Double-check paths before usingrm -rf.- Variable expansion: Variables are expanded before the command is executed. Be mindful of what the shell sees after expansion.
files="file1.txt file2.txt" rm $files # This is equivalent to rm file1.txt file2.txt # If you wanted to remove a single file named "file1.txt file2.txt", it would fail. - Globbing vs. Literal Strings: Wildcards (
*,?,[]) are expanded by the shell before being passed as arguments to a command, unless quoted.echo * # Prints all files/dirs in the current directory echo "*" # Prints the literal asterisk character PATHvariable: If a command isn’t found, it might be because its directory isn’t in your$PATHenvironment variable.- Exit Codes: Commands return an exit code (0 for success, non-zero for failure). This is used by
&&and||. Useecho $?to see the exit code of the last command.ls / # Should succeed (exit code 0) echo $? ls /nonexistent_directory # Should fail (exit code non-zero) echo $? - Permissions: Many commands (like
chown,systemctl, editing system files) require root privileges. Usesudo. - Shell vs. Program: Remember that the shell interprets commands and performs expansions/redirections before passing arguments to the actual program. This is why
echo *behaves differently fromecho "*". cdis a shell built-in: You cannot runcdin a subshell and expect the parent shell’s directory to change.
But this works:# This won't change your current directory bash -c "cd /tmp" pwd
Or directly:(cd /tmp && pwd) # Subshell runs cd, prints /tmp, parent shell is unaffected pwdcd /tmp pwd