Skip to main content
Bash beginner Lesson 2 of 22

Bash Setup and First Script

Install and configure Bash on Linux, macOS, and Windows WSL, then write and run your first shell script.

Bash on Linux

Bash is pre-installed on all major Linux distributions, which is one of the reasons it is the default choice for server scripting. You rarely need to install it, but it’s worth verifying which version you have since some features like associative arrays and the mapfile command require Bash 4 or later.

bash --version
# GNU bash, version 5.2.15(1)-release

# Check your default shell
echo $SHELL
# /bin/bash

# List available shells
cat /etc/shells

To upgrade bash on Ubuntu/Debian:

sudo apt update && sudo apt install bash

On Fedora/RHEL:

sudo dnf install bash

Bash on macOS

macOS ships with bash 3.2 (from 2007, due to licensing). For scripting you want bash 5, which adds associative arrays, improved globbing, and many other features that modern scripts rely on.

# Install via Homebrew
brew install bash

# Add to allowed shells
echo "$(brew --prefix)/bin/bash" | sudo tee -a /etc/shells

# Change your default shell (optional — zsh is fine for interactive use)
chsh -s "$(brew --prefix)/bin/bash"

Always use #!/usr/bin/env bash in your shebang — it finds the first bash in $PATH, picking up the Homebrew version on macOS rather than the system’s outdated 3.2.

Bash on Windows via WSL

WSL 2 gives you a real Linux kernel on Windows, which is the recommended way to run Bash scripts on Windows for development. It eliminates the path and line-ending issues that come with trying to run Linux scripts natively on Windows.

# In PowerShell (as Administrator)
wsl --install
# Installs Ubuntu by default, includes bash

# After reboot and Ubuntu setup:
wsl
# You're now in a bash shell
bash --version

Alternatively, Git Bash (part of Git for Windows) provides bash for simple scripting without a full Linux environment. It is good enough for most day-to-day use but lacks some Linux utilities.

The Shebang Line

The shebang (#!) is the first line of every proper bash script. It tells the OS which interpreter to use when the file is run directly. Without it, the kernel does not know whether the file is a bash script, a Python script, or something else entirely.

#!/usr/bin/env bash

Why env bash instead of /bin/bash?

  • /bin/bash is hardcoded — if bash is somewhere else (like /usr/local/bin/bash on macOS with Homebrew), the script fails silently or with a confusing error.
  • /usr/bin/env bash searches $PATH for bash, making scripts portable across systems and picking up the right version automatically.
#!/usr/bin/env bash
# Good: portable, finds Homebrew bash on macOS

#!/bin/bash
# Acceptable on Linux where bash is always at /bin/bash

#!/bin/sh
# Use only if you need strict POSIX compatibility (no bash-specific features)

Making a Script Executable

There are two ways to run a bash script, and understanding the difference matters when you are debugging permission errors or writing CI steps.

# Method 1: Pass it to the bash interpreter explicitly (no shebang needed)
bash myscript.sh

# Method 2: Execute it directly (requires shebang + execute permission)
chmod +x myscript.sh
./myscript.sh

chmod +x adds the execute bit. Check permissions with ls -l:

ls -l myscript.sh
# -rwxr-xr-x 1 user group 42 Jan 1 10:00 myscript.sh
#  ^^^
#  rwx = owner can read, write, execute

Your First Script

Writing your first script reinforces the core concepts all at once: the shebang, the safe header, variables, arguments, and command substitution. Create a file called hello.sh:

#!/usr/bin/env bash
# hello.sh — my first bash script
# This demonstrates the shebang, safe error handling, variables, and arguments.

set -euo pipefail  # exit on error, undefined vars, and pipeline failures

NAME="${1:-World}"  # use first argument, or "World" if none provided

echo "Hello, $NAME!"
echo "Today is $(date '+%A, %B %d %Y')"
echo "You are running bash $(bash --version | head -1 | awk '{print $4}')"

Run it:

chmod +x hello.sh

./hello.sh
# Hello, World!
# Today is Wednesday, January 01 2025
# You are running bash 5.2.15(1)-release

./hello.sh Alice
# Hello, Alice!

Script File Organization

A well-structured script is easier to read, debug, and hand off to teammates. The pattern below separates constants, utility functions, and logic into clearly labelled sections.

#!/usr/bin/env bash
# =============================================================================
# script-name.sh
# Description: What this script does in one sentence.
# Usage:       ./script-name.sh [options] <argument>
# Author:      Your Name
# =============================================================================

set -euo pipefail

# --- Constants ---------------------------------------------------------------
readonly SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
readonly LOG_FILE="/tmp/script-name.log"

# --- Functions ---------------------------------------------------------------
log() {
  # Writes a timestamped message to both the terminal and the log file
  echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" | tee -a "$LOG_FILE"
}

usage() {
  echo "Usage: $0 [options] <argument>"
  echo "  -h  Show this help"
  exit 0
}

# --- Main --------------------------------------------------------------------
main() {
  log "Script started"
  # ... your logic here
  log "Script finished"
}

main "$@"

Using a Text Editor

For scripts, any editor works. On a server you’ll often use:

# nano — easiest for beginners
nano myscript.sh

# vim — steep learning curve, available everywhere
vim myscript.sh

# VS Code via WSL or remote SSH
code myscript.sh

For serious script development, VS Code with the shellcheck extension is the best setup — it catches common bash mistakes in real time as you type.

Installing ShellCheck

ShellCheck is a static analysis tool for bash scripts. It’s like ESLint but for bash — it catches quoting bugs, uninitialized variables, command injection risks, and dozens of other issues before you run the script. Install it early and run it on every script you write.

# Ubuntu/Debian
sudo apt install shellcheck

# macOS
brew install shellcheck

# Run it
shellcheck myscript.sh
# Warnings with line numbers and explanations

A clean ShellCheck run means your script avoids the most common pitfalls. Many teams enforce shellcheck in CI alongside their linters for other languages.

What’s Next

With Bash set up and your first script running, the next step is learning about variables — how to store, reference, and manipulate data in bash scripts.

Frequently Asked Questions

Does Windows have Bash?
Not natively, but WSL (Windows Subsystem for Linux) gives you a full Linux environment with Bash on Windows 10/11. Git Bash is another lightweight option for basic scripting.
What does chmod +x do?
It adds the execute permission bit to a file, allowing it to be run directly as a program rather than needing to be passed explicitly to the bash interpreter.
What is a shebang line?
The first line of a script, like #!/usr/bin/env bash, tells the kernel which interpreter to use when the file is executed directly. Without it, the kernel doesn't know how to run the file.