🇯🇵 日本語 | 🇺🇸 English | 🇪🇸 Español | 🇵🇹 Português | 🇹🇭 ไทย | 🇨🇳 中文

Bash vs. Dash: Which Should You Use for Shell Scripting? A Comparison and Guide

When you're managing or developing a website, you often want to automate small, routine tasks. That's where "shell scripts" come in handy. But when you start writing one, have you ever looked at the magic-like incantation on the first line, like #!/bin/bash or #!/bin/sh, and wondered, "What's the difference?"

This difference is actually incredibly important. It's essential knowledge, especially to avoid the tragedy of "It worked perfectly on my computer, but it throws an error on the server!" In this article, we'll break down the differences between two common shells, Bash and Dash, in a way that's easy for beginners to understand, complete with code you can copy and paste to try for yourself. After reading this, you'll be able to write robust shell scripts that work in any environment!


So, What Are Bash and Dash Anyway?

First, let's introduce our two main characters (the two shells). Getting to know their strengths and personalities is the first step to getting along with them.

Bash (Bourne-Again SHell) - Everyone's Pal, the Feature-Rich Shell

Bash is the default "login shell" on many Linux systems and older versions of macOS. It's the shell that starts up when we open a terminal. Many of the convenient features we use without thinking—scrolling through command history with the arrow keys, auto-completing commands and filenames with the Tab key, using colorful prompts—are provided by Bash. It's a high-functioning, friendly shell that's extremely well-suited for direct human interaction.

Dash (Debian Almquist SHell) - The Unsung Hero, the Fast and Lightweight Shell

Dash, on the other hand, is known for being extremely lightweight and fast. It's stripped of extra features, making it specialized for executing scripts quickly. Because of this, it's used as the default shell for system startup scripts and for scripts specified with `#!/bin/sh` on Debian-based operating systems like Ubuntu. In other words, even if we don't interact with it directly very often, Dash is working hard behind the scenes of the system.


The Biggest Difference: POSIX Compliance as "Dialect" vs. "Standard Language"

The biggest difference between Bash and Dash lies in how strictly they adhere to a standard called POSIX.

That technical term might be a bit confusing at first. Simply put, POSIX is like the "standard language of the shell script world." Scripts written in this standard language are guaranteed to run the same way in any environment (OS).

The handy features we use in the terminal every day are often Bash "dialects." On many systems, /bin/sh points to a shell that only understands the "standard language" (like Dash). This is the main reason for the "works on my PC (Bash) but not on the server (/bin/sh)" phenomenon.

Writing #!/bin/bash on the first line of your script is like declaring, "This script will use Bash dialects!" allowing you to use Bash's convenient features. Conversely, writing #!/bin/sh is like requesting, "Please use the standard language!" If you want to increase portability and compatibility, the standard practice is to use #!/bin/sh and be mindful of writing POSIX-compliant code.


【Hands-on】Code Comparison: How Do Bash and Dash Differ in Syntax?

From here, let's look at specific code examples to compare Bash's "dialect" with the POSIX-compliant "standard language" that also works in Dash. To experience it "working," please copy and run these in your terminal!

1. Handling Arrays

Arrays are used when you want to handle multiple values together. In Bash, this is intuitive, but the POSIX standard has no specification for arrays. Therefore, doing the same thing in Dash requires a bit of a workaround.

The Bash Way (Dialect)

You can easily define an array using () and access elements using an index like ${my_array[1]}.

#!/bin/bash

# Define an array
fruits=("apple" "banana" "cherry")

# Echo the second element (index starts at 0)
echo ${fruits[1]}

Result:

banana

The Dash-Compatible Way (Standard Language)

When writing in a POSIX-compliant way, you use a space-separated string or the shell's positional parameters ($1, $2...) instead of an array. Here, we'll show how to use a for loop with a string. Setting the values and processing them in a for loop is a common pattern.

#!/bin/sh

# Define as a space-separated string
fruits="apple banana cherry"

# Use a for loop to output each element in order
for fruit in $fruits; do
  echo "I like $fruit!"
done

Result:

I like apple!
I like banana!
I like cherry!

2. Conditional Statements

Conditional branches like "if X, then do Y" are a fundamental part of scripting. There's a big difference here, too.

The Bash Way (Dialect)

Bash uses a more advanced test command, [[ ... ]]. It's very convenient, allowing you to connect multiple conditions with &&, perform string comparison with ==, and even do pattern matching.

#!/bin/bash

name="Taro"
age=25

# Connect two conditions with &&
if [[ "$name" == "Taro" && "$age" -gt 20 ]]; then
  echo "Welcome, Taro!"
fi

Result:

Welcome, Taro!

The Dash-Compatible Way (Standard Language)

The POSIX-compliant test command is [ ... ]. This is an older command with some limitations. For example, string comparison uses a single =, and multiple conditions must use -a (AND) or -o (OR), or be combined using multiple sets of [ ]. For safety, combining multiple [ ] is recommended.

#!/bin/sh

name="Taro"
age=25

# Write the condition using two sets of [ ]
if [ "$name" = "Taro" ] && [ "$age" -gt 20 ]; then
  echo "Welcome, Taro!"
fi

Result (Same):

Welcome, Taro!

3. String Substitution

Replacing a specific character in a variable with another is also a common task.

The Bash Way (Dialect)

In Bash, you can easily substitute strings with the syntax ${variable/old/new}.

#!/bin/bash

filename="photo_2025.jpg"

# Replace "jpg" with "png"
new_filename=${filename/jpg/png}

echo $new_filename

Result:

photo_2025.png

The Dash-Compatible Way (Standard Language)

When writing POSIX-compliant scripts, it's common to combine external commands like sed or awk for string manipulation. Here's an example using sed. It's a bit longer, but it gives you the peace of mind that it will work reliably in any environment.

#!/bin/sh

filename="photo_2025.jpg"

# Pipe the variable's content to the sed command for substitution
new_filename=$(echo "$filename" | sed 's/jpg/png/')

echo "$new_filename"

Result (Same):

photo_2025.png

Conclusion: So, Which One Should You Use?

We've looked at the differences, but the question you really want answered is, "So, which one should I use?" The answer is "it depends on the situation," but there is a recommended guideline for beginners.

Recommended Choice by Use Case

Advice for Beginners

If you're just starting to learn shell scripting, we recommend learning to write in a POSIX-compliant way with `#!/bin/sh` from the beginning. Why? Because the more compatible version covers the less compatible one. A POSIX-compliant script will run fine in Bash, but the reverse is not true. If you master the "standard language" first, you won't run into trouble no matter what environment you find yourself in.


Watch Out! Common Bash "Dialects" (Bashisms) You Might Use by Accident

It's a common story: you write code that seems perfectly fine, only to find out it was a Bash "dialect." Here are a few "Bashisms" that are particularly easy to use by mistake.

Just by avoiding these Bashisms, you will dramatically improve your script's compatibility.


Summary: Master the Convenience of Bash and the Robustness of Dash!

In this article, we've explored how to write highly compatible shell scripts by looking at the differences between Bash and Dash.

By adopting this mindset, you can prevent "it doesn't work because of the environment" troubles and write scripts that are useful in a wider range of situations. So, why not start aiming for "scripts that run anywhere" today?


Check out this article next

Dash Script Examples (if statements, loops, simple functions)