Linux Bash shell: automation, execution, and daemons


Last updated: February 26, 2026
Author: Paul Namalomba
- SESKA Computational Engineer
- SEAT Backend Developer
- Software Developer
- PhD Candidate (Civil Engineering Spec. Computational and Applied Mechanics)
Contact: kabwenzenamalomba@gmail.com
Website: paulnamalomba.github.io

OS CLI

Overview

This guide covers Bash scripting with standard input, output, and error streams (stdin, stdout, stderr), background-job scheduling through cron, and pipelines that connect commands.

Contents


1. Configuration (Windows & Linux)

The bash interpreter executes shell commands and interacts with the Linux kernel.

Unix/Linux environments

Bash is pre-installed on most Linux distributions. Check its path before writing the shebang line.

which bash
# Output typically identifies exclusively as /bin/bash or /usr/bin/bash

Windows (WSL convergence)

On Windows, use Windows Subsystem for Linux (WSL) to run Bash in a Linux environment. Opening a Windows command prompt does not start Bash.

# Open an elevated PowerShell terminal and install real Linux kernels directly
wsl --install -d Ubuntu
# Proceed to spawn native Bash sessions inside the Windows Host natively
wsl

2. Writing basic scripts (piping & execution logic)

Unix tools commonly perform one task and pass text to other tools through standard streams.

Standard streams and piping

Bash processes use three standard file descriptors: 1. stdin (0): Input stream via keyboard or incoming pipe logic. 2. stdout (1): Successful execution output text. 3. stderr (2): Error messages and diagnostics.

The Pipe operator (|) routes the stdout of the left process identically into the stdin of the right process.

#!/bin/bash
# Shebang line enforces interpreter targeting regardless of terminal state

# Example: Read a 5GB log, pipe it to grep filtering strictly for "ERROR", 
# then pipe to wc to count the absolute numerical volume of failures.
cat /var/log/syslog | grep "ERROR" | wc -l

# Appending logic onto the end of a physical file
echo "Automation process concluded at $(date)" >> /opt/scripts/status.log

# Rerouting catastrophic errors (stderr descriptor 2) silently into the void (/dev/null) 
# to ensure cleaner explicit terminal interfaces.
rm -rf /tmp/orphaned_cache 2> /dev/null

Strict mode scripts

Configure scripts to stop on unhandled errors so later commands do not run with invalid state.

#!/bin/bash
set -e  # Immediate exit if any downstream command returns a non-zero exit code.
set -o pipefail # Catch failures buried recursively inside complex pipe strings.
set -u  # Throw hard errors upon evaluating undefined environment variables.

3. Pre-execution commands (permissions & validation)

Before running a script, check its execution permissions and line endings.

The execution bit constraints

A newly created text file usually lacks execute permission. Set the execute bit before running it directly.

# Verify absolute permissions
ls -la script.sh
# Requires +x execution bindings logically 
chmod +x script.sh

Carriage return translation

Windows editors may save files with \r\n line endings, while Bash scripts on Linux use \n. The extra carriage return can produce bash: ./script.sh: /bin/bash^M: bad interpreter.

# Install tool capable of ripping Windows formatting off natively
sudo apt install dos2unix
dos2unix script.sh

4. Runtime commands (cron automation & daemons)

Run scheduled or long-lived Bash jobs through the appropriate scheduler or background process.

Daemon execution management

Detach long-running jobs from the SSH session so a dropped connection does not interrupt them.

# Execute independent physical processes dropping SIGHUP triggers
nohup ./long_running_job.sh > process.log 2>&1 &

The 2>&1 operator redirects stderr to stdout so both streams reach the same log.

The cron scheduler

The crond daemon runs scheduled jobs. Edit the crontab to set their frequency.

# Access user-specific tables natively
crontab -e

The crontab fields are: [Minute] [Hour] [Day of Month] [Month] [Day of Week]

# Execute strictly at 3:00 AM absolutely every single day.
0 3 * * * /opt/scripts/database_backup.sh >> /var/log/db_backup.log 2>&1

# Execute strictly every 15 minutes globally.
*/15 * * * * /opt/scripts/health_check.sh

5. Debugging (trace output & path traps)

Execution tracing helps you inspect command evaluation and variable values while a script runs.

Internal environment tracing

Use -x to trace evaluated commands and variable expansions during execution.

# Execute in explicit trace mode over standard script logic
bash -x script.sh
# Expected output behavior exposing the dynamic variable binding directly:
+ DB_HOST=postgres.internal.net
+ echo 'Connecting strictly to postgres.internal.net'
Connecting strictly to postgres.internal.net

Path variables & cron failures

The absolute classic pitfall associated exclusively with automation natively involves executing flawlessly from the SSH console, yet strictly failing when queued locally by cron. * The Root Cause: The interactive shell dynamically maps /usr/local/bin via .bashrc. The isolated local cron daemon natively executes explicitly mapping a heavily stripped $PATH, completely omitting locally installed tools (like Node, Python packages, etc.). * The Resolution: Use absolute paths for commands and files in the script.

# FAILURE PRONE (Assumes 'python3' and 'docker' map cleanly to PATH)
python3 manage.py
docker restart web_server

# OPERATIONAL STANDARD (Absolute binaries physically referenced)
/usr/bin/python3 /opt/app/manage.py
/usr/bin/docker restart web_server