Learning Parent and Child Shells in Bash Scripts

tommykw

Kenji Tomita

Posted on November 22, 2024

Learning Parent and Child Shells in Bash Scripts

When writing Bash scripts, you may encounter unexpected behaviors caused by the concept of parent shells and child shells. For instance, variables might not update as expected, or process IDs might not align. To understand and solve these issues, $BASHPID is a handy tool for visualizing process relationships.

This article explores how to use $BASHPID to understand the relationship between parent and child shells, while diving into the inner workings of Bash scripts.

1. What is $BASHPID?

$BASHPID is a special variable that represents the process ID of the current Bash process. It lets you identify which process is running your script.

Key Features of $BASHPID

  • Different values for parent and child shells
    • In a parent shell, $BASHPID reflects the overall script process ID, while in a child shell, it represents the new process ID.
  • Useful for tracing behavior in subshells
    • $BASHPID makes it easy to detect process forks or subprocess creations.

2. Basic Example Using $BASHPID

The following script demonstrates the difference between parent and subshells using $BASHPID.

Sample Script

#!/bin/bash

echo "Parent BASHPID: $BASHPID"

echo "Launching a subshell..."
(
  echo "Inside subshell BASHPID: $BASHPID"
)

echo "Parent again BASHPID: $BASHPID"
Enter fullscreen mode Exit fullscreen mode

Output

Parent BASHPID: 36518
Launching a subshell...
Inside subshell BASHPID: 36519
Parent again BASHPID: 36518
Enter fullscreen mode Exit fullscreen mode

Explanation

  • The parent shell (the whole script) consistently shows $BASHPID as 36518
  • The subshell creates a new process with a different PID (36519)
  • After the subshell finishes, the script returns to the parent shell with the original $BASHPID

3. Issues Caused by Parent and Child Shells

Consider the following script, where a variable fails to update conrrectly due to subshell behavior.

Problematic Script

#!/bin/bash

total_sales=0

echo "Parent process BASHPID: $BASHPID"

cat product_data.csv | while IFS=, read -r product_id price || [ -n "$product_id" ]; do
  total_sales=$((total_sales + price))
  echo "Inside while BASHPID: $BASHPID"
done

echo "Final total_sales: $total_sales"
Enter fullscreen mode Exit fullscreen mode

Input File: product_data.csv

This CSV file contains data rows only and does not include a header (e.g., product_id,price).

101,200
102,150
103,300
Enter fullscreen mode Exit fullscreen mode

Output

Parent process BASHPID: 87805
Inside while BASHPID: 87807
Inside while BASHPID: 87807
Inside while BASHPID: 87807
Final total_sales: 0
Enter fullscreen mode Exit fullscreen mode

Explanation

  • When cat ... | while is used, the while loop runs in a subshell
  • As result, changes to total_sales only apply to the subshell and do not reflect in the parent shell.
  • The output of $BASHPID inside the loop confirms that the loop is running in the subshell(87807)

4. Solving Subshell Issues

Using Redirection to Avoid Subshells

Instead of using a pipe, redirect the file input to the while loop. This ensures the loop runs in the parent shell.

Fiexed Script

#!/bin/bash

total_sales=0

echo "Parent process BASHPID: $BASHPID"

while IFS=, read -r product_id price || [ -n "$product_id" ]; do
  total_sales=$((total_sales + price))
  echo "Inside while BASHPID: $BASHPID"
done < product_data.csv

echo "Final total_sales: $total_sales"
Enter fullscreen mode Exit fullscreen mode

Output

Parent process BASHPID: 88815
Inside while BASHPID: 88815
Inside while BASHPID: 88815
Inside while BASHPID: 88815
Final total_sales: 650
Enter fullscreen mode Exit fullscreen mode

Explanation

  • Redirecting input with < ensures the while loop runs in the parent shell.
  • The parent shell's $BASHPID remains consistent(88815), and total_sales is updated correctly.

5. Summary

  1. $BASHPID provides a simple way to visualize the relationship between parent and child shells(or subshells)
  2. To address issues caused by subshells, use redirection to run loops in the parent shell.
  3. Understanding subshell creation(via pipes or parentheses) is essential for writing robust Bash scritps
đź’– đź’Ş đź™… đźš©
tommykw
Kenji Tomita

Posted on November 22, 2024

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related