Understanding /bin/dash vs /bin/bash: Symlink Behavior, Shell Differences and Practical Implications


1 views

In Unix-like systems, /bin/sh traditionally serves as the system's default shell interpreter. While many Linux distributions historically symlinked /bin/sh to Bash (/bin/bash), modern systems often point it to /bin/dash (Debian Almquist Shell) for performance reasons.

# Check where /bin/sh points:
ls -l /bin/sh
# Typical output: /bin/sh -> dash

Despite both being shells, dash and bash have significant technical differences:

  • POSIX Compliance: dash strictly follows POSIX standards, while bash includes extensions
  • Features: bash supports arrays, associative arrays, and advanced pattern matching that dash lacks
  • Startup Files: bash reads ~/.bashrc and ~/.bash_profile, dash only reads ~/.profile
  • Performance: dash is lighter and faster for system scripts

The $SHELL variable indicates your login shell, not necessarily your current shell:

# In dash:
echo $SHELL
# Output: /bin/bash (your login shell)
echo $0
# Output: dash (current shell)

When writing shell scripts, you should explicitly declare the interpreter:

#!/bin/bash
# For bash-specific features like arrays
my_array=(1 2 3)
echo ${my_array[1]}

#!/bin/sh
# For POSIX-compliant scripts
echo "This will work in any sh-compatible shell"

Most system init scripts use #!/bin/sh for portability. Here's a comparison:

# Bash-specific (won't work in dash)
if [[ $var == *.txt ]]; then
   echo "Text file"
fi

# POSIX-compliant (works in both)
case "$var" in
    *.txt) echo "Text file";;
esac

While not recommended, you can change the symlink (with caution):

sudo ln -sf /bin/bash /bin/sh
# Verify:
ls -l /bin/sh

Remember this might break system scripts expecting dash behavior.

To test if a feature works in dash:

dash -c 'your_command_here'
# Example:
dash -c 'echo ${BASH_VERSION}'
# Output: (empty) - dash doesn't have this variable

Many Linux users get confused when they discover that /bin/sh isn't pointing to their preferred shell (often bash) but instead links to /bin/dash. This isn't an error - it's a deliberate design choice in modern Unix-like systems.

The apparent contradiction where echo $SHELL shows /bin/bash while running in dash occurs because:

# $SHELL shows your login shell, not current shell
$ dash
$ echo $SHELL
/bin/bash
$ echo $0
dash

Dash (Debian Almquist Shell) became the default /bin/sh in Debian/Ubuntu systems because:

  • It's significantly lighter than bash
  • Boots faster (critical for init scripts)
  • Implements POSIX standards more strictly

While dash is POSIX-compliant, bash includes many extensions:

# This works in bash but fails in dash
array=(1 2 3)
echo ${array[1]}

# Dash requires:
set -- 1 2 3
echo $2

To properly identify your current shell:

# Method 1: Read /proc
cat /proc/$$/comm

# Method 2: Check $0
echo $0

# Method 3: Use ps
ps -p $$

Use dash for:

  • System startup scripts
  • Cases where POSIX compliance is required
  • Resource-constrained environments

Use bash for:

  • Interactive sessions
  • Scripts using bash-specific features
  • Development environments

To modify the symlink (not recommended for system stability):

sudo ln -sf /bin/bash /bin/sh

# Verify with:
ls -l /bin/sh

Always specify the interpreter explicitly:

#!/bin/bash
# or
#!/bin/dash

For maximum portability, write POSIX-compliant scripts and test with:

dash your_script.sh