Przejdลบ do treล›ci

๐Ÿ”ง Extended Parameters and Expansions

Beyond basic variable assignment (var=value), shells offer powerful mechanisms for manipulating parameters, performing substitutions, and handling missing values gracefully.

๐Ÿงญ Why Extended Expansions Matter

In production scripts, you'll frequently encounter: - Variables that might be unset - Strings that need transformation - Default values that should apply conditionally - Indirect references to variable names

Extended parameter expansions handle all these cases without external tools, making scripts faster and more portable.


๐Ÿงฎ Basic Parameter Expansion Recap

Before diving into advanced features, let's review the fundamentals:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
name="John Doe"

# Length
echo ${#name}           # 8

# Substring extraction
echo ${name:0:4}        # John (from position 0, 4 chars)
echo ${name:5}          # Doe (from position 5 to end)

# Replace first occurrence
echo ${name/John/Jane}  # Jane Doe

# Replace all occurrences
echo ${name//o/0}       # Jane D0e

๐Ÿงช Default Values

Unset or Empty Variables

Provide fallback when variable doesn't exist or is empty:

1
2
3
# If $EDITOR is unset or empty, use "nano"
editor="${EDITOR:-nano}"
echo "Using editor: $editor"

This is extremely useful for configuration:

1
2
3
4
5
6
7
8
#!/bin/sh
: "${LOG_LEVEL:=INFO}"
: "${MAX_RETRIES:=3}"
: "${API_URL:=https://api.example.com}"

echo "Log level: $LOG_LEVEL"
echo "Max retries: $MAX_RETRIES"
echo "API URL: $API_URL"

The : builtin is a no-op โ€” it's used here purely for the side effect of parameter expansion.


Assign Default Permanently

Use := to set the variable if it's unset:

1
2
: "${CACHE_DIR:=/tmp/cache}"
mkdir -p "$CACHE_DIR"

Subsequent uses will see the assigned value:

1
echo "$CACHE_DIR"  # /tmp/cache (not empty anymore)

Require Variable to Be Set

Fail fast if required variable is missing:

1
: "${DATABASE_URL:?Error: DATABASE_URL is required}"

If DATABASE_URL is unset or empty, the script exits with:

1
script.sh: line 5: DATABASE_URL: Error: DATABASE_URL is required

This is perfect for mandatory configuration.


๐Ÿง  Pattern-Based Substitutions

Remove Prefix

Strip shortest matching prefix:

1
2
3
4
5
6
7
path="/usr/local/bin/script.sh"

# Remove everything up to last slash
basename="${path##*/}"     # script.sh

# Remove everything up to first slash
dirname="${path#/*}"       # usr/local/bin/script.sh

Remove Suffix

Strip shortest matching suffix:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
filename="document.tar.gz"

# Remove extension
name="${filename%.*}"      # document.tar

# Remove specific suffix
name="${filename%.gz}"     # document.tar

# Remove longest match (all extensions)
name="${filename%%.*}"     # document

๐Ÿงช Advanced Replacement Patterns

Case Modification

Convert case without external tools:

1
2
3
4
5
6
str="Hello World"

echo "${str^^}"   # HELLO WORLD (uppercase)
echo "${str,,}"   # hello world (lowercase)
echo "${str^}"    # Hello World (first char upper)
echo "${str,}"    # hello World (first char lower)

โš ๏ธ Bash 4.0+ / Zsh only โ€” not POSIX.


Search and Replace

Replace patterns within strings:

1
2
3
4
5
6
7
8
9
path="/home/user/documents/file.txt"

# Replace first occurrence
new="${path/\/home\/user/\/opt/shared}"
# Result: /opt/shared/documents/file.txt

# Replace all occurrences
new="${path//\//_}"
# Result: _home_user_documents_file.txt

Useful for sanitizing paths or generating identifiers.


๐Ÿง  Indirect Variable References

Access a variable whose name is stored in another variable:

1
2
3
varname="USER"
value="${!varname}"   # Equivalent to $USER
echo "$value"         # root (or current user)

Practical example โ€” configuration map:

1
2
3
4
5
6
7
8
9
DB_HOST="db.example.com"
DB_PORT="5432"
DB_NAME="myapp"

for var in DB_HOST DB_PORT DB_NAME; do
    key="${var#DB_}"           # HOST, PORT, NAME
    value="${!var}"
    echo "$key=$value"
done

Output:

1
2
3
HOST=db.example.com
PORT=5432
NAME=myapp

โš ๏ธ Not POSIX โ€” avoid in portable scripts.


๐Ÿงช Array-Like Behavior

Bash supports arrays, but POSIX shells don't. Simulate with positional parameters:

1
2
3
4
5
6
7
8
9
set -- apple banana cherry

echo "First: $1"           # apple
echo "Count: $#"           # 3

# Iterate
for item; do
    echo "Item: $item"
done

Or use delimited strings:

1
2
3
4
items="apple,banana,cherry"
IFS=',' read -ra arr <<< "$items"
echo "${arr[0]}"           # apple
echo "${arr[@]}"           # apple banana cherry

๐Ÿงพ Portability Notes

Feature POSIX Bash Zsh
${var:-default} โœ… โœ… โœ…
${var:=default} โœ… โœ… โœ…
${var:?error} โœ… โœ… โœ…
${var^^} (uppercase) โŒ โœ… โœ…
${var,,} (lowercase) โŒ โœ… โœ…
${!var} (indirect) โŒ โœ… โœ…
Arrays (${arr[@]}) โŒ โœ… โœ…

๐Ÿงพ Summary

  • Use ${var:-default} for optional configuration.
  • Use ${var:?error} for mandatory values.
  • Pattern substitutions (##, %%, //) are powerful and portable.
  • Indirect references and case conversion are convenient but not portable.
  • Simulate arrays in POSIX shells with $@ or delimited strings.

๐Ÿ‘‰ Continue to: Conditionals and Tests