From bash-development
Details Bash 5.3 features like in-shell command substitution (${ command; }), REPLY capture (${| command; }), GLOBSORT, and loadable builtins with examples and benchmarks. Useful for modern Bash scripting.
How this skill is triggered — by the user, by Claude, or both
Slash command
/bash-development:bash-53-featuresThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Released in July 2025, Bash 5.3 introduces significant enhancements including revolutionary command substitution syntax, new variables, loadable builtins, and improved C standard conformance.
Released in July 2025, Bash 5.3 introduces significant enhancements including revolutionary command substitution syntax, new variables, loadable builtins, and improved C standard conformance.
${ command; }Execute commands without forking, dramatically improving performance:
# Traditional command substitution (creates subshell)
result=$(echo "Hello, World")
# NEW: In-shell command substitution (no fork!)
# Note: a space (or tab/newline/|) is required after the opening '{'
result=${ echo "Hello, World"; }
# Practical example: Fast variable assignment
config_value=${ grep "^timeout=" config.txt | cut -d= -f2; }
# Performance comparison function
benchmark_substitution() {
local i
local start end
echo "Testing traditional substitution..."
start="${EPOCHREALTIME}"
for ((i = 0; i < 1000; i++)); do
result=$(echo "${i}")
done
end="${EPOCHREALTIME}"
printf 'Traditional: %.4f seconds\n' \
"$(awk "BEGIN {print ${end} - ${start}}")"
echo "Testing new in-shell substitution..."
start="${EPOCHREALTIME}"
for ((i = 0; i < 1000; i++)); do
result=${ echo "${i}"; }
done
end="${EPOCHREALTIME}"
printf 'In-shell: %.4f seconds\n' \
"$(awk "BEGIN {print ${end} - ${start}}")"
}
benchmark_substitution
Benefits:
${| command; }Execute commands and automatically store output in REPLY. Note: REPLY is local to the
substitution — its value is restored after completion, so capture it immediately:
Benefits:
# String manipulation - use in-shell for efficiency
filename="document.txt"
basename=${ echo "${filename%.*}"; }
extension=${ echo "${filename##*.}"; }
# Output capture - use REPLY for clarity
${| df -h / | tail -1 | awk '{print $5}'; }
disk_usage="${REPLY}"
echo "Disk usage: ${disk_usage}"
# Complex pipelines - traditional might still be clearer
result=$(cat file.txt | grep pattern | sort | uniq)
Control the sorting order of filename and pathname expansion. The specifier is optionally
prefixed with + (ascending, default) or - (descending):
Available sort specifiers:
name — Alphabetical by filenamesize — By file sizemtime — By modification timeatime — By access timectime — By inode change timeblocks — By allocated block countnumeric — Numeric sort on leading digits in filenamenosort — Disable sorting (glob order)+ (ascending, default) or - (descending)compgen with Variable StorageStore completions directly in a variable:
read with Readline Completion (-E)Interactive input with autocompletion:
# Enable readline completion during read
choose_file() {
local file
echo "Enter filename (tab for completion):"
read -e -r -E -p "> " file
if [[ -f "${file}" ]]; then
echo "Selected: ${file}"
return 0
else
echo "File not found: ${file}"
return 1
fi
}
choose_file
# Practical example: Interactive configuration
configure_app() {
local config_file
echo "Select configuration file:"
read -e -r -E -p "Config: " config_file
if [[ -f "${config_file}" ]]; then
${| grep -c "^[^#]" "${config_file}"; }
local line_count="${REPLY}"
echo "Found ${line_count} active configuration lines"
fi
}
source with Path (-p)Specify search path for sourced scripts:
printf EnhancementsNew options for multibyte strings and representations:
# Enhanced printf options
printf '%q\n' "string with spaces" # Shell-quoted output
# NEW: Multibyte string support improvements
text="Hello, 世界"
printf 'Length: %d bytes\n' "${#text}"
# Practical example: Safe command construction
build_command() {
local -a args=("$@")
local arg cmd=""
for arg in "${args[@]}"; do
cmd+=$(printf '%q ' "${arg}")
done
echo "Safe command: ${cmd}"
}
build_command ls "-l" "file with spaces.txt"
kv - Key-Value ArraysCreate associative arrays from key-value data. Note: The kv builtin existence is
confirmed in Bash 5.3; the exact interface shown below is illustrative — verify with
help kv after loading:
strptime - Date ParsingParse textual dates into Unix timestamps. Note: The strptime builtin existence is
confirmed in Bash 5.3; the exact interface shown below is illustrative — verify with
help strptime after loading:
fltexpr - Floating-Point CalculationsPerform floating-point arithmetic without external tools:
Enhanced POSIX compliance:
# Enable POSIX mode
set -o posix
# String comparisons now follow locale rules
[[ "ä" < "z" ]] # Locale-dependent comparison
# Improved POSIX conformance in builtins
# test, trap, wait, bind all more strictly conformant
# Practical example: Portable script header
#!/usr/bin/env bash
if [[ "${BASH_VERSINFO[0]}" -ge 5 ]] && [[ "${BASH_VERSINFO[1]}" -ge 3 ]]; then
# Bash 5.3+ available, use modern features
USE_MODERN_FEATURES=1
else
# Fall back to POSIX mode for portability
set -o posix
USE_MODERN_FEATURES=0
fi
More detailed error messages:
Bash 5.3 improves conformance to modern C standards (the build minimum remains C90):
Note: This primarily affects developers compiling Bash from source, not end users.
${ cmd; }) dramatically reduces overheadGLOBSORT# Benchmark: Traditional vs new substitution
benchmark() {
local iterations=10000
local i start end
start="${EPOCHREALTIME}"
for ((i = 0; i < iterations; i++)); do
result=$(echo test)
done
end="${EPOCHREALTIME}"
printf 'Traditional: %.4f seconds\n' \
"$(awk "BEGIN {print ${end} - ${start}}")"
start="${EPOCHREALTIME}"
for ((i = 0; i < iterations; i++)); do
result=${ echo test; }
done
end="${EPOCHREALTIME}"
printf 'In-shell: %.4f seconds\n' \
"$(awk "BEGIN {print ${end} - ${start}}")"
}
benchmark
Most scripts compatible, but consider:
# Take advantage of new command substitution for performance
# OLD:
for file in *; do
size=$(stat -f%z "${file}" 2>/dev/null)
done
# NEW (faster):
for file in *; do
${| stat -f%z "${file}" 2>/dev/null; }
size="${REPLY}"
done
# Use GLOBSORT for better file processing
GLOBSORT="-mtime"
for file in *.log; do
process_recent_log "${file}"
done
# Leverage new builtins where appropriate
# Instead of: awk calculation
# Use: fltexpr for floating-point math
# Check for Bash 5.3 features
if [[ "${BASH_VERSINFO[0]}" -ge 5 ]] && [[ "${BASH_VERSINFO[1]}" -ge 3 ]]; then
echo "Bash 5.3+ features available"
CAN_USE_INSITU_SUBSTITUTION=1
CAN_USE_GLOBSORT=1
else
echo "Bash version: ${BASH_VERSION}"
CAN_USE_INSITU_SUBSTITUTION=0
CAN_USE_GLOBSORT=0
fi
For broader Bash development patterns and best practices, see:
npx claudepluginhub jamie-bitflight/claude_skills --plugin bash-developmentExplains Bash 5.3 features including in-shell ${ command; } substitution, ${| command; } REPLY syntax, enhanced read -E, and source -p. Useful for performant shell scripts.
Explains Bash 5.2 features like variable handling enhancements, nameref improvements, readline 8.2 integration, and array operations with practical examples. Use for Bash 5.2-specific scripting or queries.
Writes and reviews defensive Bash scripts for production automation, CI/CD, and system utilities. Enforces strict error handling, safe argument parsing, and portable patterns.