11: Production Bash Scripting & Defensive Programming
Tested Stacks:
GATK 4.6.1
Samtools 1.21
Nextflow 24.10
Seurat v5.1
Python 3.12
Prerequisites: Basic Linux CLI & Sequencing Formats
📚 Chapter 11 of 13
0% Course Completed
Chapter 11: Production Bash Scripting & Defensive Programming
Writing individual commands on the terminal is sufficient for testing, but biological studies require analyzing dozens or hundreds of patient samples consistently. Bash scripting automates multi-step workflows. However, poorly written scripts fail silently: if an alignment tool fails due to missing memory, a naive script will continue executing downstream steps on empty files, corrupting your final results. Defensive Bash programming ensures your pipelines fail immediately and cleanly when an error occurs.
The Holy Grail: set -euo pipefail
Every production bioinformatics bash script should include this line at the top:
set -euo pipefail-e(errexit): Exit immediately if any command returns a non-zero (error) status.-u(nounset): Treat unset variables as errors and exit immediately (prevents catastrophic bugs likerm -rf $UNSET_VAR/*).-o pipefail: If any tool in a pipeline stream (cmd1 | cmd2 | cmd3) fails, the entire pipeline returns an error status rather than masking it.
1. Complete Production Script Template
Save this as align_cohort.sh:
#!/usr/bin/env bash
# ==============================================================================
# Script Name: align_cohort.sh
# Description: Automated paired-end alignment with defensive error handling
# Author: Omics Research Portal
# ==============================================================================
set -euo pipefail
# 1. Setup Logging Function
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*"
}
# 2. Cleanup Function on Script Exit or Failure
cleanup() {
local exit_code=$?
if [[ $exit_code -ne 0 ]]; then
log "[ERROR] Pipeline failed with exit status code: $exit_code"
else
log "[SUCCESS] Pipeline finished successfully!"
fi
}
trap cleanup EXIT
# 3. Validate Command Line Arguments
if [[ $# -lt 2 ]]; then
echo "Usage: $0 <reference.fa> <raw_fastq_dir>"
exit 1
fi
REFERENCE_GENOME="$1"
FASTQ_DIR="$2"
OUTPUT_DIR="aligned_bams"
THREADS=8
# 4. Validate Input File Existence
if [[ ! -f "$REFERENCE_GENOME" ]]; then
log "[ERROR] Reference genome file '$REFERENCE_GENOME' does not exist!"
exit 1
fi
mkdir -p "$OUTPUT_DIR"
log "Starting alignment cohort using reference: $REFERENCE_GENOME"
# 5. Iterate Over Paired-End Samples
for R1 in "${FASTQ_DIR}"/*_R1.fastq.gz; do
# Check if files matching the pattern exist
[[ -e "$R1" ]] || { log "No FASTQ files found matching pattern!"; exit 1; }
# Derive Sample Name and Paired Reverse Read
SAMPLE_NAME=$(basename "$R1" _R1.fastq.gz)
R2="${FASTQ_DIR}/${SAMPLE_NAME}_R2.fastq.gz"
OUT_BAM="${OUTPUT_DIR}/${SAMPLE_NAME}.sorted.bam"
if [[ ! -f "$R2" ]]; then
log "[WARNING] Reverse read '$R2' missing for sample '$SAMPLE_NAME'. Skipping."
continue
fi
log "Processing sample: $SAMPLE_NAME"
# Execute Alignment Stream
bwa-mem2 mem -t "$THREADS" \
-R "@RG\tID:${SAMPLE_NAME}\tSM:${SAMPLE_NAME}\tPL:ILLUMINA" \
"$REFERENCE_GENOME" "$R1" "$R2" | \
samtools sort -@ 4 -o "$OUT_BAM" -
samtools index "$OUT_BAM"
log "Finished sample: $SAMPLE_NAME -> $OUT_BAM"
done
log "All cohort samples processed successfully."2. Executing Your Script
# 1. Grant execute permissions
chmod +x align_cohort.sh
# 2. Run the script with positional arguments
./align_cohort.sh /references/GRCh38.fa ./raw_reads/
⚠️
Common Pitfalls & Troubleshooting Checklist
- Java Heap Exhaustion (GATK / Picard): If processes terminate with
java.lang.OutOfMemoryError, set your environment variable explicitly:export _JAVA_OPTIONS="-Xmx16g -Djava.io.tmpdir=/tmp". - Index Timestamp Mismatch: If tools complain that a BAM index is missing or out of date, regenerate with
samtools index -@ 4 sample.bam. - Conda Channel Conflicts: Avoid ABI incompatibilities between bioconda and conda-forge by setting strict priority:
conda config --set channel_priority strict. - Chromosome Naming Contamination: Always verify whether reference FASTA headers use
chr1or1; divergent naming causes silent alignment drops.
Was this guide helpful to your research?
Help us maintain 100% accurate, peer-reviewed bioinformatics standards.