Language
日本語
English

Caution

JavaScript is disabled in your browser.
This site uses JavaScript for features such as search.
For the best experience, please enable JavaScript before browsing this site.

  1. Home
  2. Shell Script Dictionary
  3. Command Substitution

Command Substitution

Since: POSIX(sh互換)

In shell scripts, command substitution with $() captures the output of a command as a string and allows it to be assigned to a variable or passed as an argument to another command. The legacy backtick syntax (``) offers the same functionality, but $() is now the recommended form.

Basic Syntax of $()

Writing $(command) executes the command inside the parentheses in a subshell, and its standard output is expanded inline at that position. Trailing newlines are automatically removed.

SyntaxDescription
result=$(command)Assigns the command's output to variable result.
echo "Today is $(date '+%Y-%m-%d')"Can be embedded inside a string.
for file in $(ls *.sh); do ... doneThe command's output can be used as the list in a loop.
lines=$(cat file | wc -l)The result of an entire pipeline can be assigned.
outer=$(echo "value: $(echo inner)")Can be nested. The innermost substitution is expanded first.

Difference Between $() and Backticks

Backticks (`command`) behave identically to $(), but they are harder to work with and less readable in several ways. The advantage of $() becomes especially clear when nesting is needed.

Comparison$()Backticks ``
NestingCan be nested directly. $(echo $(date))Inner backticks must be escaped, making the code hard to read. `echo \`date\``
VisibilityOpening and closing parentheses are symmetric and easy to distinguish.
Backslash handlingBackslashes inside the parentheses retain their literal meaning.Backslashes inside backticks may receive special interpretation.
POSIX complianceDefined in POSIX; works in bash, sh, and zsh.Also POSIX-compliant, but nested behavior can be implementation-dependent.
Recommendation$() is recommended for new scripts.Knowledge of backticks is needed when reading legacy scripts.

Important Notes on Command Substitution

NoteDescription
Trailing newline removal$() automatically strips trailing newlines from command output. Newlines in the middle of output are preserved.
Wrap in quotesWithout double quotes like "$(command)", word splitting occurs on spaces and newlines in the output.
Runs in a subshellThe content of $() runs in a separate process (subshell), so variable changes inside it are not reflected in the outer shell.
Exit statusThe assignment result=$(command) itself always returns exit status 0 (success). To check the command's exit status, separate the assignment from the status check.

Sample Code

yakuza_command_sub_basic.sh
#!/bin/bash
# -----------------------------------------------
#  Basic sample demonstrating dynamic construction
#  of character information using command substitution
#  (Yakuza / Like a Dragon series)
# -----------------------------------------------

# -----------------------------------------------
#  1. Assign a command result to a variable
#     -> Store the output of $(date) in TODAY
# -----------------------------------------------
TODAY=$(date '+%Y-%m-%d')
echo "Run date: ${TODAY}"
echo ""

# -----------------------------------------------
#  2. Embed inside a string
#     -> Expand the output of echo directly into the string
# -----------------------------------------------
KIRYU="Kiryu Kazuma"
GREETING="${KIRYU} says: $(echo 'I will walk my own path.')"
echo "${GREETING}"
echo ""

# -----------------------------------------------
#  3. Use a command's output as loop input
#     -> Process a list of character names line by line
# -----------------------------------------------
CHARACTERS="Kiryu Kazuma
Majima Goro
Saejima Taiga
Akiyama Shun
Shinada Tatsuo"

echo "=== Character list ==="
# Process each line of echo output in a while loop
# Set IFS (field separator) to newline before reading
while IFS= read -r name; do
    # Get the character count of the name using wc -m (excluding newline)
    char_count=$(echo -n "${name}" | wc -m)
    echo "  ${name} (${char_count} chars)"
done <<< "${CHARACTERS}"
echo ""

# -----------------------------------------------
#  4. Combine with arithmetic
#     -> Use the bc command inside $() for floating-point calculation
# -----------------------------------------------
echo "=== Statistics: number of game appearances ==="
# Number of game appearances for each character (sample data)
KIRYU_GAMES=8
MAJIMA_GAMES=7
SAEJIMA_GAMES=3
AKIYAMA_GAMES=3
SHINADA_GAMES=1

TOTAL=$((KIRYU_GAMES + MAJIMA_GAMES + SAEJIMA_GAMES + AKIYAMA_GAMES + SHINADA_GAMES))
AVG=$(echo "scale=1; ${TOTAL} / 5" | bc)

echo "  Kiryu Kazuma:   ${KIRYU_GAMES} games"
echo "  Majima Goro:    ${MAJIMA_GAMES} games"
echo "  Saejima Taiga:  ${SAEJIMA_GAMES} games"
echo "  Akiyama Shun:   ${AKIYAMA_GAMES} games"
echo "  Shinada Tatsuo: ${SHINADA_GAMES} games"
echo "  Total:          ${TOTAL} games"
echo "  Average:        ${AVG} games"
chmod +x yakuza_command_sub_basic.sh
./yakuza_command_sub_basic.sh
Run date: 2026-03-27

Kiryu Kazuma says: I will walk my own path.

=== Character list ===
  Kiryu Kazuma (12 chars)
  Majima Goro (11 chars)
  Saejima Taiga (13 chars)
  Akiyama Shun (12 chars)
  Shinada Tatsuo (14 chars)

=== Statistics: number of game appearances ===
  Kiryu Kazuma:   8 games
  Majima Goro:    7 games
  Saejima Taiga:  3 games
  Akiyama Shun:   3 games
  Shinada Tatsuo: 1 games
  Total:          22 games
  Average:        4.4 games
yakuza_command_sub_nest.sh
#!/bin/bash
# -----------------------------------------------
#  Nested $() and comparison with backticks
#  Demonstrating behavior with Yakuza characters
# -----------------------------------------------

# -----------------------------------------------
#  1. Nesting $() (inner substitution expands first)
#     -> The outer $() uses the result of the inner $()
# -----------------------------------------------
echo "=== 1. Nested \$() ==="

# Count the characters in a name
# Inner: output the name with echo
# Outer: count the characters with wc -m
NAME="Kiryu Kazuma"
CHAR_COUNT=$(echo -n "$(echo ${NAME})" | wc -m)
echo "Character count of \"${NAME}\": ${CHAR_COUNT}"

# Example of deeper nesting (3 levels)
# From inside: date -> remove spaces with tr -> extract first 10 chars with cut
DATESTAMP=$(cut -c1-10 <<< "$(tr -d ' ' <<< "$(date '+%Y - %m - %d')")")
echo "Formatted date: ${DATESTAMP}"
echo ""

# -----------------------------------------------
#  2. Comparison with backticks
#     -> The same operation written with backticks
# -----------------------------------------------
echo "=== 2. Comparison with backticks ==="

CHAR_A=$(echo -n "${NAME}" | wc -m)           # using $() (recommended)
CHAR_B=`echo -n "${NAME}" | wc -m`            # using backticks (not recommended)

echo "\$() result:        ${CHAR_A}"
echo "Backtick result:   ${CHAR_B}"
echo "Both produce the same result"
echo ""

# -----------------------------------------------
#  3. Ease of nesting comparison
#     -> Backticks require escaping and are hard to read
# -----------------------------------------------
echo "=== 3. Ease of nesting ==="

CHARACTERS="Kiryu Kazuma Majima Goro Saejima Taiga Akiyama Shun Shinada Tatsuo"

# Nested $() (readable)
COUNT_DOLLAR=$(echo "$(echo ${CHARACTERS})" | wc -w)
echo "\$() nested - word count: ${COUNT_DOLLAR}"

# Nested backticks (inner backticks must be escaped)
COUNT_BACK=`echo "\`echo ${CHARACTERS}\`" | wc -w`
echo "Backtick nested - word count: ${COUNT_BACK}"
echo ""

# -----------------------------------------------
#  4. Effect of quoting
#     -> Without double quotes, word splitting occurs
# -----------------------------------------------
echo "=== 4. Effect of quoting ==="

RESULT_UNQUOTED=$(echo "Majima Goro   Saejima Taiga   Akiyama Shun")
RESULT_QUOTED="$(echo "Majima Goro   Saejima Taiga   Akiyama Shun")"

# Without quotes, multiple spaces are collapsed to one
echo "Unquoted: ${RESULT_UNQUOTED}"

# With double quotes, spaces are preserved
echo "Quoted:   ${RESULT_QUOTED}"
echo ""

# -----------------------------------------------
#  5. Checking exit status
#     -> Checking $? after assignment always returns 0
#     -> The command and assignment must be separated
# -----------------------------------------------
echo "=== 5. Checking exit status ==="

# Bad practice: checking $? at the same time as assignment only reveals assignment success
output=$(grep "Kiryu" <<< "Kiryu Kazuma protects Kamurocho")
echo "\$? after assignment: $?"   # always 0 (the assignment itself succeeded)

# Good practice: separate assignment from status check
grep -q "Majima" <<< "Majima Goro appears everywhere"
STATUS=$?
if [ "${STATUS}" -eq 0 ]; then
    echo "Majima Goro: matched (exit status: ${STATUS})"
else
    echo "Majima Goro: no match (exit status: ${STATUS})"
fi
chmod +x yakuza_command_sub_nest.sh
./yakuza_command_sub_nest.sh
=== 1. Nested $() ===
Character count of "Kiryu Kazuma": 12
Formatted date: 2026-03-27

=== 2. Comparison with backticks ===
$() result:        12
Backtick result:   12
Both produce the same result

=== 3. Ease of nesting ===
$() nested - word count: 5
Backtick nested - word count: 5

=== 4. Effect of quoting ===
Unquoted: Majima Goro Saejima Taiga Akiyama Shun
Quoted:   Majima Goro   Saejima Taiga   Akiyama Shun

=== 5. Checking exit status ===
$? after assignment: 0
Majima Goro: matched (exit status: 0)

Practical Usage Patterns

PatternSyntaxDescription
Use current date in a filenameLOG="log_$(date '+%Y%m%d').txt"Automatically appends the execution date to the filename.
Count lines in a filelines=$(wc -l < file.txt)Stores the result of wc -l in a variable for use in conditional logic.
Check if a command existspath=$(which git)Gets the full path of a command; check if it is empty to determine presence.
Get hostname or IPHOST=$(hostname)Dynamically retrieves server information within the script.
Use output from another scriptval=$(bash sub.sh)Makes the standard output of a sub-script available in the calling script.

Notes

Command substitution ($()) in shell scripts expands the result of a command as a string inline. Assigning to a variable with result=$(command) is the most fundamental usage, applicable everywhere from getting the date to reading file information and using output from other commands. The legacy backtick (``) syntax behaves identically, but $() is superior in that nesting is intuitive, backslash handling is straightforward, and the syntax is visually clear — in modern shell scripts, $() is the standard choice. When output may contain spaces or newlines, wrapping in double quotes as "$(command)" prevents unintended word splitting. Checking $? after an assignment only reveals whether the assignment succeeded, not the command's exit status — separate the command from the assignment when the exit status matters. See also Pipes for combining command substitution with pipes.

If you find any errors or copyright issues, please .