advanced-array-patterns
Advanced bash array patterns including indexed and associative arrays, mapfile/readarray, slicing, and array manipulation (2025). PROACTIVELY activate for: (1) using bash arrays effectively, (2) reading file contents into an array via mapfile/readarray, (3) authoring associative arrays (declare -A), (4) iterating arrays safely under set -u, (5) deleting/inserting array elements, (6) joining and splitting arrays, (7) passing arrays to functions via nameref (declare -n), (8) array slicing and parameter expansion, (9) sorting and deduplicating arrays in pure bash. Provides: indexed and associative array reference, mapfile and readarray recipes, nameref-based pass-by-reference, slicing/expansion patterns, and gotchas for unset variables and word splitting.
What this skill does
## CRITICAL GUIDELINES
### Windows File Path Requirements
**MANDATORY: Always Use Backslashes on Windows for File Paths**
When using Edit or Write tools on Windows, you MUST use backslashes (`\`) in file paths, NOT forward slashes (`/`).
---
# Advanced Bash Array Patterns (2025)
## Overview
Comprehensive guide to bash arrays including indexed arrays, associative arrays, mapfile/readarray, and advanced manipulation patterns following 2025 best practices.
## Indexed Arrays
### Declaration and Initialization
```bash
#!/usr/bin/env bash
set -euo pipefail
# Method 1: Direct assignment
files=("file1.txt" "file2.txt" "file with spaces.txt")
# Method 2: Compound assignment
declare -a numbers=(1 2 3 4 5)
# Method 3: Individual assignment
fruits[0]="apple"
fruits[1]="banana"
fruits[2]="cherry"
# Method 4: From command output (CAREFUL with word splitting)
# ✗ DANGEROUS - splits on spaces
files_bad=$(ls)
# ✓ SAFE - preserves filenames with spaces
mapfile -t files_good < <(find . -name "*.txt")
# Method 5: Brace expansion
numbers=({1..100})
letters=({a..z})
```
### Array Operations
```bash
#!/usr/bin/env bash
set -euo pipefail
arr=("first" "second" "third" "fourth" "fifth")
# Length
echo "Length: ${#arr[@]}" # 5
# Access elements
echo "First: ${arr[0]}"
echo "Last: ${arr[-1]}" # Bash 4.3+
echo "Second to last: ${arr[-2]}"
# All elements (properly quoted for spaces)
for item in "${arr[@]}"; do
echo "Item: $item"
done
# All indices
for idx in "${!arr[@]}"; do
echo "Index $idx: ${arr[$idx]}"
done
# Slice (offset:length)
echo "${arr[@]:1:3}" # second third fourth
# Slice from offset to end
echo "${arr[@]:2}" # third fourth fifth
# Append element
arr+=("sixth")
# Insert at position (complex)
arr=("${arr[@]:0:2}" "inserted" "${arr[@]:2}")
# Remove element by index
unset 'arr[2]'
# Remove by value (all occurrences)
arr_new=()
for item in "${arr[@]}"; do
[[ "$item" != "second" ]] && arr_new+=("$item")
done
arr=("${arr_new[@]}")
# Check if empty
if [[ ${#arr[@]} -eq 0 ]]; then
echo "Array is empty"
fi
# Check if element exists
contains() {
local needle="$1"
shift
local item
for item in "$@"; do
[[ "$item" == "$needle" ]] && return 0
done
return 1
}
if contains "third" "${arr[@]}"; then
echo "Found 'third'"
fi
```
### Array Transformation
```bash
#!/usr/bin/env bash
set -euo pipefail
arr=("apple" "banana" "cherry" "date")
# Map (transform each element)
upper_arr=()
for item in "${arr[@]}"; do
upper_arr+=("${item^^}") # Uppercase
done
# Filter
filtered=()
for item in "${arr[@]}"; do
[[ ${#item} -gt 5 ]] && filtered+=("$item")
done
# Join array to string
IFS=','
joined="${arr[*]}"
unset IFS
echo "$joined" # apple,banana,cherry,date
# Split string to array
IFS=',' read -ra split_arr <<< "one,two,three"
# Unique values
declare -A seen
unique=()
for item in "${arr[@]}"; do
if [[ -z "${seen[$item]:-}" ]]; then
seen[$item]=1
unique+=("$item")
fi
done
# Sort array
readarray -t sorted < <(printf '%s\n' "${arr[@]}" | sort)
# Reverse array
reversed=()
for ((i=${#arr[@]}-1; i>=0; i--)); do
reversed+=("${arr[$i]}")
done
# Or using tac
readarray -t reversed < <(printf '%s\n' "${arr[@]}" | tac)
```
## Associative Arrays (Bash 4+)
### Declaration and Usage
```bash
#!/usr/bin/env bash
set -euo pipefail
# MUST declare with -A
declare -A config
# Assignment
config["host"]="localhost"
config["port"]="8080"
config["debug"]="true"
# Or compound assignment
declare -A user=(
[name]="John Doe"
[email]="[email protected]"
[role]="admin"
)
# Access
echo "Host: ${config[host]}"
echo "User: ${user[name]}"
# Default value if key missing
echo "${config[missing]:-default}"
# Check if key exists
if [[ -v config[host] ]]; then
echo "Host is set"
fi
# Alternative check
if [[ -n "${config[host]+x}" ]]; then
echo "Host key exists (even if empty)"
fi
# All keys
echo "Keys: ${!config[@]}"
# All values
echo "Values: ${config[@]}"
# Length (number of keys)
echo "Size: ${#config[@]}"
# Iterate
for key in "${!config[@]}"; do
echo "$key = ${config[$key]}"
done
# Delete key
unset 'config[debug]'
# Clear entire array
config=()
```
### Real-World Associative Array Patterns
```bash
#!/usr/bin/env bash
set -euo pipefail
# Configuration parser
parse_config() {
local config_file="$1"
declare -gA CONFIG # Global associative array
while IFS='=' read -r key value; do
# Skip comments and empty lines
[[ "$key" =~ ^[[:space:]]*# ]] && continue
[[ -z "$key" ]] && continue
# Trim whitespace
key="${key//[[:space:]]/}"
value="${value#"${value%%[![:space:]]*}"}" # Left trim
value="${value%"${value##*[![:space:]]}"}" # Right trim
CONFIG["$key"]="$value"
done < "$config_file"
}
# Usage
parse_config "/etc/myapp.conf"
echo "Database: ${CONFIG[database]:-not set}"
# Counter/frequency map
count_words() {
local file="$1"
declare -A word_count
while read -ra words; do
for word in "${words[@]}"; do
# Normalize: lowercase, remove punctuation
word="${word,,}"
word="${word//[^a-z]/}"
[[ -n "$word" ]] && ((word_count[$word]++))
done
done < "$file"
# Print sorted by count
for word in "${!word_count[@]}"; do
echo "${word_count[$word]} $word"
done | sort -rn | head -10
}
# Caching pattern
declare -A CACHE
cached_expensive_operation() {
local key="$1"
# Check cache
if [[ -n "${CACHE[$key]+x}" ]]; then
echo "${CACHE[$key]}"
return 0
fi
# Compute and cache
local result
result=$(expensive_computation "$key")
CACHE["$key"]="$result"
echo "$result"
}
# JSON-like nested data (using delimited keys)
declare -A data
data["user.name"]="John"
data["user.email"]="[email protected]"
data["user.address.city"]="NYC"
data["user.address.zip"]="10001"
# Access nested
echo "City: ${data[user.address.city]}"
```
## mapfile / readarray (Bash 4+)
### Basic Usage
```bash
#!/usr/bin/env bash
set -euo pipefail
# Read file into array (each line = element)
mapfile -t lines < file.txt
# Or equivalently:
readarray -t lines < file.txt
# -t removes trailing newlines
# Without -t, each element includes \n
# Process each line
for line in "${lines[@]}"; do
echo "Line: $line"
done
# Read from command output
mapfile -t files < <(find . -name "*.sh")
# Read from here-doc
mapfile -t data <<'EOF'
line1
line2
line3
EOF
```
### Advanced mapfile Options
```bash
#!/usr/bin/env bash
set -euo pipefail
# -n COUNT: Read at most COUNT lines
mapfile -t -n 10 first_10 < large_file.txt
# -s COUNT: Skip first COUNT lines
mapfile -t -s 1 skip_header < data.csv # Skip header row
# -O INDEX: Start at INDEX instead of 0
existing_array=("a" "b")
mapfile -t -O "${#existing_array[@]}" existing_array < more_data.txt
# -d DELIM: Use DELIM instead of newline (Bash 4.4+)
# Read NUL-delimited data (safe for filenames with newlines)
mapfile -t -d '' files < <(find . -name "*.txt" -print0)
# -C CALLBACK: Execute callback every QUANTUM lines
# -c QUANTUM: Number of lines between callbacks (default 5000)
process_chunk() {
local index=$1
echo "Processing lines around index $index" >&2
}
export -f process_chunk
mapfile -t -c 1000 -C process_chunk lines < huge_file.txt
```
### CSV Processing with mapfile
```bash
#!/usr/bin/env bash
set -euo pipefail
# Parse CSV file
parse_csv() {
local csv_file="$1"
local -n result_array="$2" # nameref (Bash 4.3+)
while IFS=',' read -ra row; do
result_array+=("${row[*]}") # Store as delimited string
done < "$csv_file"
}
# Better: Store as 2D array simulation
declare -A csv_data
row_num=0
while IFS=',' read -ra fields; do
for col_num in "${!fields[@]}"; do
csv_data["$row_num,$col_num"]="${fields[$col_num]}"
done
((row_num++))
done < data.csv
# Access cell
echo "Row 2, Col 3: ${csv_data[2Related in General
modeling-omnistudio-epc-catalog
IncludedSalesforce Industries CME EPC product-modeling skill for Product2-based catalog creation. Use when creating EPC products, configuring product attributes, building offer bundles with Product Child Items, or reviewing EPC DataPack JSON metadata for product catalog changes. TRIGGER when: user creates or updates Product2 EPC records, AttributeAssignment payloads, AttributeMetadata/AttributeDefaultValues, Offer bundles, or ProductChildItem relationships. DO NOT TRIGGER when: designing OmniScripts/FlexCards/Integration Procedures (use building-omnistudio-omniscript, building-omnistudio-flexcard, or building-omnistudio-integration-procedure), implementing Apex business logic (use generating-apex), or troubleshooting deployment pipelines (use deploying-metadata).
relationship-science-coach
IncludedUse this skill for direct, practical adult relationship coaching: couples conflict, repair, trust, marriage, dating, flirting, attachment patterns, emotional connection, sex, desire differences, eroticism, kink negotiation, affection, love languages, breakups, and long-term passion. Draw on Gottman, EFT and Hold Me Tight, attachment science, modern sex research, Perel, Nagoski, Kerner, Schnarch, Love and Stosny, and flexible love-language tools. Be concrete and low-hedge. Redirect only for imminent danger, abuse, coercive control, minors, non-consent, self-harm, stalking, or medical/legal/psychiatric decisions.
building-sf-integrations
IncludedSalesforce integration architecture and runtime plumbing with 120-point scoring. Use this skill to set up Named Credentials, External Credentials, External Services, REST/SOAP callout patterns, Platform Events, and Change Data Capture. TRIGGER when: user sets up Named Credentials, External Services, REST/SOAP callouts, Platform Events, CDC, or touches .namedCredential-meta.xml files. DO NOT TRIGGER when: Connected App/OAuth config (use configuring-connected-apps), Apex-only logic (use generating-apex), or data import/export (use handling-sf-data).
venue-templates
IncludedAccess comprehensive LaTeX templates, formatting requirements, and submission guidelines for major scientific publication venues (Nature, Science, PLOS, IEEE, ACM), academic conferences (NeurIPS, ICML, CVPR, CHI), research posters, and grant proposals (NSF, NIH, DOE, DARPA). This skill should be used when preparing manuscripts for journal submission, conference papers, research posters, or grant proposals and need venue-specific formatting requirements and templates.
let-fate-decide
IncludedDraws the 12 Houses of the Zodiac Tarot spread to inject entropy into planning when prompts are vague, ambiguous, or casually delegated. Interprets the spread to guide next steps. Use when the user says 'let fate decide', 'YOLO', 'whatever', 'idk', or other nonchalant phrases, makes Yu-Gi-Oh references, or when you are about to arbitrarily pick between multiple reasonable approaches. Prefer over ask-questions-if-underspecified when the user's tone is casual or playful rather than precision-seeking.
net-ops
IncludedCross-platform network troubleshooting (Windows, macOS, Linux) via local or remote shell. Use for: DNS broken, can't resolve hostnames, nslookup/dig works but apps fail, NRPT, WFP, scutil, /etc/resolver, systemd-resolved, /etc/resolv.conf, NetworkManager, VPN DNS leak residue (ProtonVPN/Mullvad/WireGuard/AnyConnect), AV/firewall blocking DNS or DoH, Tailscale DNS interaction, intermittent connectivity, remote diagnostics over SSH.