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
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
- Linux Bash shell: automation, execution, and daemons
- Overview
- Contents
- 1. Configuration (Windows \& Linux)
- 2. Writing basic scripts (piping \& execution logic)
- 3. Pre-execution commands (permissions \& validation)
- 4. Runtime commands (cron automation \& daemons)
- 5. Debugging (trace output \& path traps)
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