| |

Bash Scripting 03 ๐Ÿง User Input โ€” Reading environment variables and interactive prompts

โฑ๏ธ Estimated read: 10 min | |

The previous chapter covered the variable types and the declare attributes. This chapter covers the mechanisms that populate the variables from the outside: the environment variables inherited from the parent process and the interactive prompts that read the user’s input. In Bash, the environment variables are the exported variables that the shell receives from the parent. The read builtin is the mechanism for the interactive prompt. The critical distinction is between the environment variable ($VAR that the script inherits) and the local variable (VAR=value that the script sets). The read builtin has the options (-p, -s, -n, -t, -r) that control the prompt, the echo, the length, the timeout, and the backslash handling. The IFS variable controls the field splitting, and the misuse of the read without the IFS is the source of the leading/trailing whitespace issues.

Key point: The environment variables are the exported variables from the parent, accessed with the $VAR. The read builtin reads the line from the standard input and assigns the words to the variables. The read -p "prompt" VAR displays the prompt. The read -s VAR hides the input (for the passwords). The read -n N VAR reads exactly N characters. The read -t T VAR times out after T seconds. The read -r VAR prevents the backslash interpretation. The IFS= read -r line is the correct form for reading the raw line.


Why user input requires a specific mental model

The environment problem. The environment variables are not the same as the shell variables. The VAR=value in the parent is the shell variable, not the environment. The child process (the script) does not see it unless the parent exported it. The export VAR=value marks the variable for the inheritance. The env command lists the environment, and the set lists the shell variables. The printenv VAR shows the environment variable .

The read problem. The read VAR reads the line from the standard input, splits it on the IFS (the default whitespace), and assigns the first word to the VAR (and the remaining words to the remaining variables, if any). The read VAR1 VAR2 assigns the first word to the VAR1 and the rest of the line to the VAR2. The read -a ARRAY assigns the words to the array. The read without the variable name assigns to the REPLY .

The IFS problem. The IFS is the internal field separator. The default is the space, the tab, and the newline. The read splits on the IFS. The IFS= read -r line clears the IFS and preserves the leading and trailing whitespace. The read -r line without the IFS= strips the leading and trailing whitespace. The raw line reading is the common use case for the config files .

The prompt problem. The read -p "Enter the name: " NAME displays the prompt and reads the input. The prompt goes to the standard error, not the standard output. The read -s suppresses the echo, which is the required for the passwords. The read -t 5 times out after the 5 seconds, and the $? returns the 142 (the 128 + 14 for the SIGALRM) .

The validation problem. The read does not validate the input. The user can enter the empty string, the spaces, the malicious characters. The script must validate the input: the [[ -z "$VAR" ]] for the empty, the [[ "$VAR" =~ ^[0-9]+$ ]] for the numeric, the case for the allowed values. The validation is the script’s responsibility, not the read‘s.

The trade-off. The read is the simple and the standard. The getopts (the chapter 126 in the LFCS series) is the correct for the command-line arguments. The environment variables are the correct for the secrets (the CI/CD) and the configuration. The interactive prompt is the correct for the scripts that require the human interaction.


a. The environment variables

The environment variables are the exported variables from the parent.

#!/bin/bash
echo "HOME: $HOME"
echo "USER: $USER"
echo "PATH: $PATH"
echo "SHELL: $SHELL"

The $HOME, the $USER, the $PATH, and the $SHELL are the standard environment variables. The printenv lists the environment. The env is the same. The set lists the shell variables and the functions.

The custom environment variable.

#!/bin/bash
# The parent exports the variable
export APP_ENV="production"
./script.sh
# The script reads the $APP_ENV

# The script inherits the environment
echo "Env: $APP_ENV"
# production

The export APP_ENV="production" makes the variable visible to the child. The script reads the $APP_ENV. The unexported variable is the invisible.

The environment in the systemd service.

# /etc/systemd/system/myapp.service
[Service]
Environment="APP_ENV=production"
EnvironmentFile=/etc/myapp/env
ExecStart=/usr/local/bin/myapp

The Environment= is the inline. The EnvironmentFile= is the file. The systemd passes the environment to the service. The service reads the $APP_ENV .


b. The read builtin and the prompt

The read reads the line from the standard input.

#!/bin/bash
read -p "Enter the name: " NAME
echo "Hello, $NAME"

The read -p displays the prompt and reads the input. The $NAME is the variable.

The password prompt.

#!/bin/bash
read -s -p "Enter the password: " PASSWORD
echo
echo "Password length: ${#PASSWORD}"

The -s suppresses the echo. The echo after the read prints the newline (the -s does not print it).

The timeout.

#!/bin/bash
if read -t 5 -p "Enter the value (5s): " VALUE; then
    echo "You entered: $VALUE"
else
    echo "Timeout"
fi

The -t 5 times out after the 5 seconds. The $? returns the non-zero. The if checks the result.

The exact character count.

#!/bin/bash
read -n 1 -p "Continue? (y/n) " ANSWER
echo
echo "You chose: $ANSWER"

The -n 1 reads exactly one character. The echo prints the newline (the read -n does not wait for the Enter).


c. The IFS and the raw line

The IFS= read -r line preserves the leading and trailing whitespace.

#!/bin/bash
# The config file with the spaces
while IFS= read -r line; do
    echo "[$line]"
done < /etc/config.txt

The IFS= clears the field separator. The -r prevents the backslash interpretation. The line includes the leading and trailing whitespace. The [$line] shows the exact boundaries.

The read without the IFS=.

#!/bin/bash
# The read without the IFS
read -r line
# The leading and trailing whitespace is stripped

The read -r without the IFS= strips the whitespace. The IFS= read -r preserves it. The difference is the IFS assignment before the read.

The multiple variables.

#!/bin/bash
read -p "Enter name and age: " NAME AGE
echo "Name: $NAME, Age: $AGE"
# Input: Alice 30
# The NAME is "Alice", the AGE is "30"

The read NAME AGE assigns the first word to the NAME and the rest of the line to the AGE. The last variable gets the rest (including the spaces).


Complete Example Session

# ============================================
# PART 1: THE ENVIRONMENT VARIABLES
# ============================================

echo "HOME: $HOME"
echo "USER: $USER"
echo "PATH: $PATH"

# ============================================
# PART 2: THE CUSTOM ENVIRONMENT
# ============================================

export APP_ENV="prod"
bash -c 'echo "Env: $APP_ENV"'
# Env: prod

# ============================================
# PART 3: THE SIMPLE READ
# ============================================

read -p "Enter name: " NAME
echo "Hello, $NAME"

# ============================================
# PART 4: THE PASSWORD
# ============================================

read -s -p "Password: " PASS
echo
echo "Length: ${#PASS}"

# ============================================
# PART 5: THE TIMEOUT
# ============================================

if read -t 5 -p "Value (5s): " VAL; then
    echo "Got: $VAL"
else
    echo "Timeout"
fi

# ============================================
# PART 6: THE SINGLE CHARACTER
# ============================================

read -n 1 -p "Continue? (y/n) " ANS
echo
echo "Choice: $ANS"

# ============================================
# PART 7: THE RAW LINE
# ============================================

while IFS= read -r line; do
    echo "[$line]"
done < /etc/config.txt

# ============================================
# PART 8: THE MULTIPLE VARIABLES
# ============================================

read -p "Name and age: " NAME AGE
echo "Name: $NAME, Age: $AGE"

# ============================================
# PART 9: THE VALIDATION
# ============================================

read -p "Count: " COUNT
if [[ "$COUNT" =~ ^[0-9]+$ ]]; then
    echo "Valid: $COUNT"
else
    echo "Invalid"
fi

The nine parts trace the user input: the environment, the custom environment, the simple read, the password, the timeout, the single character, the raw line, the multiple variables, and the validation.


Quick Reference

The read Options

OptionPurpose
-pThe prompt
-sThe silent (the password)
-n NRead N characters
-t TThe timeout in seconds
-rThe raw (no backslash)
-aThe array
-dThe delimiter

The Environment

CommandPurpose
export VARMark for the children
printenvList the environment
envThe same
setThe shell variables

The IFS Usage

FormEffect
read -r lineStrips the whitespace
IFS= read -r linePreserves the whitespace
IFS=: read -r a bSplits on the :

The Validation

TestPurpose
[[ -z "$VAR" ]]The empty
[[ "$VAR" =~ ^[0-9]+$ ]]The numeric
caseThe allowed values

Best Practices

โœ… Do This:

read -r -p "Name: " NAME
<!-- Use the -r for the backslash -->                # โœ…
while IFS= read -r line; do ...; done < file
<!-- Use the IFS= for the raw lines -->              # โœ…
if [[ "$COUNT" =~ ^[0-9]+$ ]]; then ... fi
<!-- Validate the numeric input -->                  # โœ…

โŒ Don’t Do This:

read -p "Name: " NAME
<!-- The backslash is the interpreted -->            # โŒ
read line
<!-- The leading whitespace is stripped -->         # โŒ
# Trust the input without the validation
<!-- The malicious or empty input -->                # โŒ

Common Pitfalls

PitfallWhy It HappensFix
The whitespace strippedNo IFS=IFS= read -r
The backslash interpretedNo -rread -r
The password visibleNo -sread -s
The numeric check failsNo validation[[ =~ ]]
The environment not visibleNot exportedexport VAR

Real-World Examples

1. The Prompt

read -p "Name: " NAME

2. The Password

read -s -p "Password: " PASS

3. The Timeout

read -t 5 -p "Value: " VAL

4. The Single Character

read -n 1 -p "Continue? " ANS

5. The Raw Line

IFS= read -r line

6. The File Loop

while IFS= read -r line; do echo "$line"; done < file

7. The Multiple Variables

read -p "Name and age: " NAME AGE

8. The Validation

[[ "$VAL" =~ ^[0-9]+$ ]]

9. The Export

export APP_ENV="prod"

10. The Print Environment

printenv | grep APP_

Visual

The Environment Inheritance

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  Parent shell                                โ”‚
โ”‚  โ”œโ”€โ”€ APP_ENV="prod" (exported)               โ”‚
โ”‚  โ””โ”€โ”€ LOCAL="local" (not exported)            โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                   โ”‚
                   โ”‚ ./script.sh
                   โ–ผ
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  The script (child)                          โ”‚
โ”‚  โ”œโ”€โ”€ APP_ENV (visible)                       โ”‚
โ”‚  โ””โ”€โ”€ LOCAL (not visible)                     โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

The read Flow

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  read -p "Prompt: " VAR                      โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                   โ”‚
                   โ–ผ
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  The prompt to the stderr                    โ”‚
โ”‚  The input from the stdin                    โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                   โ”‚
                   โ–ผ
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  The line split on the IFS                   โ”‚
โ”‚  The words assigned to the variables         โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Summary

ItemValue
The environmentexport VAR
The listprintenv
The readread VAR
The promptread -p
The passwordread -s
The timeoutread -t N
The raw lineIFS= read -r
The validation[[ =~ ]]

Key takeaways:

  • The environment variables are the exported. The export VAR makes the variable visible to the child. The printenv lists the environment. The unexported variable is the invisible.
  • The read reads the line and splits on the IFS. The read -p prompts. The read -s hides. The read -t times out. The -n reads the characters.
  • The IFS= read -r preserves the whitespace. The read -r strips it. The raw line reading is the correct for the config files and the text processing.
  • The validation is the script’s responsibility. The read does not validate. The [[ =~ ]] for the numeric, the -z for the empty, the case for the allowed values.
  • The environment is the secret mechanism. The CI/CD variables, the systemd Environment=, the .env files. The environment variables are the standard for the configuration and the secrets.

Remember: The export is the environment. The read is the input. The IFS= is the raw. The -r is the backslash. The validation is the safety. The exam tests the read options and the environment variables.

Was this helpful?


Stop using slow, ad-bloated tool sites! ๐Ÿคฎ

๐Ÿ”Ž Search “KandZ Tools” on Google to use many professional utilities for free.

KandZ.me is the ultimate minimalist hub for:
โœ… Finance (Mortgage, Interest, Inflation)
โœ… Tech (Base64, JSON, Dev Suite, IP)
โœ… Health (BMI, BMR, TDEE)
โœ… Productivity (Timer, Workspace, QR)

โšก๏ธ Fast & Private
๐Ÿ”’ No data leaves your device
๐Ÿ’Ž 100% Free

๐Ÿ”— Use it now: https://tools.kandz.me
๐Ÿ”– Bookmark itโ€”youโ€™ll need it later!