Heredoc Patterns Reference
Overview
Heredocs (Here Documents) allow you to pass multi-line strings to commands without escaping. Master these patterns for efficient shell scripting.
Basic Syntax
| Pattern | Behavior | Use Case |
|---|---|---|
|
Variables expanded, commands executed |
Dynamic content |
|
Literal string, no expansion |
Scripts, configs with |
|
Strips leading tabs (not spaces) |
Indented scripts |
|
Here-string (single line) |
Quick single-line input |
Pattern 1: Execute Multiple Commands
bash <<'EOF'
cd ~/atelier/_bibliotheca/domus-siem-ops
git remote remove origin
git remote add origin git@github.com:EvanusModestus/domus-siem-ops.git
git remote add gitlab git@gitlab.com:EvanusModestus/domus-siem-ops.git
git remote add gitea git@gitea-01.inside.domusdigitalis.dev:evanusmodestus/domus-siem-ops.git
git remote -v
EOF
Pattern 2: Git Commit with Heredoc
git commit -m "$(cat <<'EOF'
feat(siem): Add QRadar threat detection queries
- Add lateral movement detection (SMB, RDP, WinRM)
- Add data exfiltration queries
- Add authentication monitoring
- All queries use attributes for environment values
EOF
)"
Pattern 3: Create Configuration Files
sudo tee /etc/NetworkManager/conf.d/wifi_backend.conf > /dev/null <<'EOF'
[device]
wifi.backend=wpa_supplicant
EOF
Pattern 4: Create Scripts On-The-Fly
cat > /tmp/quick-audit.sh <<'EOF'
#!/bin/bash
echo "=== System Audit ==="
echo "Hostname: $(hostname)"
echo "Uptime: $(uptime -p)"
echo "Disk: $(df -h / | tail -1)"
echo "Memory: $(free -h | grep Mem)"
EOF
chmod +x /tmp/quick-audit.sh
Pattern 5: SSH Remote Execution
ssh user@server <<'EOF'
cd /var/log
grep -i error syslog | tail -20
systemctl status nginx
df -h
EOF
Pattern 6: Conditional Heredoc
cat <<EOF
Server: ${SERVER:-localhost}
Port: ${PORT:-8080}
Debug: ${DEBUG:-false}
EOF
Pattern 7: Append to File
cat >> ~/.zshrc <<'EOF'
# domus-siem-ops alias
alias dsiem='cd ~/atelier/_bibliotheca/domus-siem-ops'
alias domus-siem='cd ~/atelier/_bibliotheca/domus-siem-ops'
EOF
Pattern 8: JSON Payload
curl -X POST https://api.example.com/endpoint \
-H "Content-Type: application/json" \
-d "$(cat <<'EOF'
{
"name": "domus-siem-ops",
"description": "Vendor-agnostic SIEM operations",
"private": true,
"auto_init": false
}
EOF
)"
Pattern 9: Multi-Command Pipeline
cat <<'EOF' | while read -r cmd; do
echo "Running: $cmd"
eval "$cmd"
done
git status --short
git log --oneline -5
git remote -v
EOF
Pattern 10: AQL Query Execution
# Store query in heredoc, execute via API
QUERY=$(cat <<'EOF'
SELECT
sourceip AS "Source",
destinationip AS "Destination",
COUNT(*) AS "Connections"
FROM flows
WHERE destinationport = 445
GROUP BY sourceip, destinationip
ORDER BY "Connections" DESC
LAST 24 HOURS
EOF
)
curl -sk "https://$QRADAR_HOST/api/ariel/searches" \
-H "SEC: $QRADAR_TOKEN" \
-d "query_expression=$QUERY"
Pattern 11: Database Operations
psql -U postgres <<'EOF'
SELECT username, last_login, failed_attempts
FROM users
WHERE failed_attempts > 5
ORDER BY failed_attempts DESC;
EOF
Pattern 12: Netapi Bulk Operations
# Create multiple ISE objects
bash <<'EOF'
dsource d000 dev/network
# Create dACL
netapi ise create-dacl -n "Linux-AD-Auth" --acl "permit udp any any eq 53
permit tcp any any eq 88
permit tcp any any eq 389
permit tcp any any eq 636
deny ip any 10.0.0.0/8"
# Create authorization profile
netapi ise create-authz-profile -n "Linux-AD-Auth-Profile" \
--dacl "Linux-AD-Auth" \
--vlan "DATA_VLAN"
echo "Done creating ISE objects"
EOF
Pattern 13: Indented with Tab Stripping
if [[ "$DEPLOY" == "true" ]]; then
cat <<-EOF
Deploying to production...
Server: $SERVER
Version: $VERSION
EOF
fi
Use actual tabs (not spaces) for <←EOF stripping to work.
|
Pattern 14: Here-String (Single Line)
# Quick single-line input
grep "error" <<< "$LOG_CONTENT"
# Convert to uppercase
tr '[:lower:]' '[:upper:]' <<< "hello world"
# JSON parsing
jq '.name' <<< '{"name": "domus-siem-ops"}'
Pattern 15: Function with Heredoc
create_config() {
local hostname=$1
local ip=$2
cat <<EOF
[server]
hostname = $hostname
ip_address = $ip
port = 8443
ssl = true
EOF
}
# Usage
create_config "ise-01" "10.50.1.20" > /tmp/server.conf
Anti-Patterns (Avoid)
# BAD: Unquoted EOF with variables you don't want expanded
cat <<EOF
Password: $PASSWORD # This will be empty or wrong!
EOF
# GOOD: Quote EOF
cat <<'EOF'
Password: $PASSWORD # Literal $PASSWORD
EOF
# BAD: Mixing tabs and spaces with <<-
# GOOD: Use only tabs for indentation with <<-
Quick Reference Card
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β HEREDOC QUICK REFERENCE β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β Execute commands: bash <<'EOF' ... EOF β
β Git commit: git commit -m "$(cat <<'EOF' ... EOF)"β
β Create file: cat > file <<'EOF' ... EOF β
β Append to file: cat >> file <<'EOF' ... EOF β
β Tee with sudo: sudo tee file <<'EOF' ... EOF β
β SSH remote: ssh user@host <<'EOF' ... EOF β
β Curl JSON: curl -d "$(cat <<'EOF' ... EOF)" β
β Strip tabs: <<-EOF (use actual tabs) β
β Single line: <<< "string" β
β Variable expansion: <<EOF (unquoted) β
β Literal/no expand: <<'EOF' (quoted) β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ