The Quoting Pitfall in Shell Variable References: Why echo $var Shows Unexpected Results

Nov 20, 2025 · Programming · 14 views · 7.8

Keywords: Shell Variable Reference | Field Splitting | Pathname Expansion | Double Quotes | echo Command | Shell Programming Pitfalls

Abstract: This article provides an in-depth analysis of common issues in shell variable referencing, including wildcard expansion, pathname expansion, and field splitting. Through multiple practical examples, it demonstrates how unquoted variable references lead to unexpected behaviors, explains the mechanisms of field splitting and pathname expansion in detail, and presents correct variable referencing methods. The paper emphasizes the importance of always quoting variable references to help developers avoid common pitfalls in shell scripting.

Problem Phenomenon Analysis

In shell programming, variable assignment and variable referencing are two distinct processes. Many developers encounter situations where variables are correctly assigned but display unexpected results when referenced. The root cause of this phenomenon lies in the additional processing steps that the shell performs on unquoted variable references.

Specific Case Analysis

Let's examine this issue through several typical scenarios:

Wildcard Expansion Issue

When variables contain wildcards, unquoted references trigger pathname expansion:

$ var="/* Foobar is free software */"
$ echo $var
/bin /boot /dev /etc /home /initrd.img /lib /lib64 /media /mnt /opt /proc ...

Here, /* expands to list all files and directories in the root directory instead of being output literally.

Character Class Expansion Issue

Bracket expressions undergo character class expansion when unquoted:

$ var=[a-z]
$ echo $var
c

[a-z] expands to the first matching lowercase letter instead of the literal string.

Newline Handling Issue

Multi-line content gets merged into a single line when referenced without quotes:

$ cat file
foo
bar
baz

$ var=$(cat file)
$ echo $var
foo bar baz

Newlines are converted to spaces, causing multi-line content to merge.

Whitespace Compression Issue

Multiple consecutive spaces or tabs get compressed during output:

$ var="       title     |    count"
$ echo $var
title | count

$ var=$'key\tvalue'
$ echo $var
key value

Multiple spaces compress to single spaces, and tabs convert to spaces.

Root Cause Analysis

The shell performs the following processing steps on unquoted variable references:

Field Splitting

When variables are unquoted, their values are first split according to the IFS (Internal Field Separator) environment variable. By default, IFS contains space, tab, and newline characters, therefore:

Pathname Expansion

Each split word containing wildcards (*, ?, [], etc.) undergoes pathname expansion:

Parameter Passing

All expanded parameters are passed to the echo command, which by default separates all arguments with single spaces when outputting. This explains why:

Correct Solution

The solution to all these problems is simple: always use double quotes when referencing variables.

Correct Usage Examples

$ var="/* Foobar is free software */"
$ echo "$var"
/* Foobar is free software */

$ var=[a-z]
$ echo "$var"
[a-z]

$ var=$(cat file)
$ echo "$var"
foo
bar
baz

$ var="       title     |    count"
$ echo "$var"
       title     |    count

$ var=$'key\tvalue'
$ echo "$var"
key	value

Mechanism of Double Quotes

When variables are double-quoted:

  1. Variables are substituted with their values
  2. No field splitting occurs
  3. No pathname expansion occurs
  4. Values are passed to the target command as-is

Best Practice Recommendations

Based on the above analysis, we propose the following shell programming best practices:

Always Quote Variable References

Unless you explicitly need field splitting and pathname expansion, always use double quotes when referencing variables:

# Correct approach
echo "$variable"
cp "$source" "$destination"

# Incorrect approach
echo $variable
cp $source $destination

Special Case Handling

In certain specific situations, you might actually need field splitting:

# Example requiring field splitting
files="file1.txt file2.txt file3.txt"
rm $files  # This deletes three files

# If quoted, no files are deleted
rm "$files"  # Attempts to delete a file named "file1.txt file2.txt file3.txt"

Using Tools for Assistance

We recommend using static analysis tools like shellcheck to check for quoting issues in shell scripts:

# Install shellcheck
# Ubuntu/Debian: sudo apt-get install shellcheck
# macOS: brew install shellcheck

# Check scripts
shellcheck your_script.sh

Deep Understanding of Shell Processing

To thoroughly understand this issue, one must comprehend the shell's command processing pipeline:

Complete Command Processing Steps

  1. Tokenization: Break command line into words and operators
  2. Expansion: Perform various expansions in order
    • Brace expansion
    • Tilde expansion
    • Parameter and variable expansion
    • Command substitution
    • Arithmetic expansion
    • Word splitting (only when unquoted)
    • Pathname expansion (only when unquoted)
  3. Quote Removal: Remove all quoting characters
  4. Command Execution: Execute the final command

Timing of Quote Effects

Quotes take effect after tokenization but before expansion:

Practical Application Scenarios

Understanding correct variable referencing is crucial for writing robust shell scripts:

File Operation Scenarios

# Handling filenames with spaces
filename="My Document.txt"

# Wrong: splits into two arguments
cp $filename backup/

# Correct: preserves filename integrity
cp "$filename" "backup/"

String Processing Scenarios

# Handling strings with special characters
var="Hello * World"

# Wrong: * gets expanded
echo $var

# Correct: outputs literally
echo "$var"

Command Line Argument Construction

# Building arguments containing spaces
options="-name \"*.txt\" -size +1M"

# Wrong: parameter parsing errors
find . $options

# Correct: using arrays is safer
options=(-name "*.txt" -size +1M)
find . "${options[@]}"

Conclusion

The quoting pitfall in shell variable references is a common trap in shell programming. By deeply understanding the mechanisms of field splitting and pathname expansion, we can avoid these errors. Remember this simple rule: unless you explicitly need field splitting and pathname expansion, always use double quotes when referencing variables. This habit will help you write more robust and predictable shell scripts.

In practical development, combining the use of static analysis tools like shellcheck can further ensure code quality. Mastering these fundamental concepts will enable you to better understand and debug various strange behaviors in shell scripts.

Copyright Notice: All rights in this article are reserved by the operators of DevGex. Reasonable sharing and citation are welcome; any reproduction, excerpting, or re-publication without prior permission is prohibited.