How to Check if a Shell Variable Starts with # (Hash Symbol) in bash/sh Scripting


3 views

When working with shell scripts (bash/sh), you might need to check if a string variable begins with specific characters. A common use case is identifying comment lines that start with the hash symbol (#). The intuitive approach using [ myvar = #* ] doesn't work because:


# This won't work:
if [ myvar = #* ]; then
    echo "Starts with #"
fi

Method 1: Using Parameter Expansion

The most efficient way in bash:


myvar="#comment asfasfasdf"
if [[ "$myvar" == \#* ]]; then
    echo "Variable starts with #"
fi

Method 2: POSIX-compliant Solution

For maximum portability across different shells:


myvar="#comment asfasfasdf"
case "$myvar" in
    \#*) echo "Starts with #" ;;
    *) echo "Doesn't start with #" ;;
esac

Method 3: Using grep

Alternative approach using pattern matching:


if echo "$myvar" | grep -q '^#'; then
    echo "Found hash prefix"
fi
  • Forgetting to quote variables ("$myvar" vs $myvar)
  • Using [ ] instead of [[ ]] in bash
  • Not escaping the # character properly

The parameter expansion method (Method 1) is fastest as it doesn't spawn subshells or external processes. The case statement (Method 2) is nearly as fast and more portable.

Here's a practical script that processes lines in a file:


#!/bin/sh

process_file() {
    while IFS= read -r line; do
        case "$line" in
            \#*) 
                echo "Skipping comment: $line"
                ;;
            *) 
                echo "Processing: $line"
                # Your logic here
                ;;
        esac
    done < "$1"
}

process_file "input.txt"

Many developers coming from other programming languages often stumble when trying to perform pattern matching in shell scripts. The example below shows a common mistake:

#!bin/sh
myvar="#comment asfasfasdf"
if [ myvar = #* ]

This approach fails because the [ ] test construct doesn't support pattern matching in the same way that other programming languages do.

Here are several reliable methods to check if a shell variable starts with a hash character:

Method 1: Using Parameter Expansion

if [[ "${myvar}" =~ ^# ]]; then
    echo "Variable starts with #"
fi

This uses bash's regex operator =~. Note that this requires bash, not plain sh.

Method 2: POSIX-compliant Approach

case "$myvar" in
    "#"*) echo "Found leading hash" ;;
    *) echo "No hash" ;;
esac

This works in all POSIX-compliant shells and is the most portable solution.

Method 3: Using String Slicing

if [ "${myvar:0:1}" = "#" ]; then
    echo "Starts with hash"
fi

This checks the first character directly. Note that some older shells might not support this syntax.

When testing variables that might be empty, always quote them:

myvar=""
if [ "${myvar:0:1}" = "#" ]; then
    echo "This won't trigger"
else
    echo "Handle empty case"
fi

Also consider variables that might contain only whitespace before the hash:

myvar="   #comment"
if [[ "${myvar#"${myvar%%[![:space:]]*}"}" =~ ^# ]]; then
    echo "Starts with hash after trimming whitespace"
fi

For scripts processing many lines or running frequently, the case statement tends to be fastest in benchmarks. The regex approach is more flexible but slightly slower.