Posted on
Artificial Intelligence

Artificial Intelligence Process Optimisation

Author
  • User
    linuxbash
    Posts by this author
    Posts by this author

AI Process Optimization for Bash Users: Turn Logs Into Speedups

Your cron job ran all night and still missed the window? Most shell pipelines run on faith: we toss data at scripts, hope they scale, and only notice inefficiencies when they hurt. The good news: a small dose of AI—built on the telemetry your Linux box already gives you—can turn guesswork into measurable speedups. You don’t need a GPU, a data lake, or a team of data scientists. You need Bash, a few lightweight tools, and a handful of Python.

This post shows how to instrument your processes, detect regressions, predict runtimes, and auto-tune command-line parameters with practical, copy-pasteable snippets. The value: fewer surprises, faster jobs, and smarter scheduling.

Why this is worth your time

  • Linux emits rich metrics (time, CPU, RSS, I/O) that are perfect for machine learning on tabular data.

  • Even simple models (isolation forests, random forests) on a laptop can reveal anomalies and predict durations with useful accuracy.

  • AI-guided parameter tuning (threads, compression level, block size) can yield double-digit improvements without touching your source code.

  • You can keep everything local and scriptable—ideal for CI, cron, and headless servers.

Prerequisites

We’ll rely on:

  • GNU time for reproducible timing

  • sysstat (pidstat) for sampling

  • jq for JSON handling

  • GNU parallel for concurrency

  • pigz for a real-world example

  • Python 3 with pip for ML utilities

Install with your package manager:

  • apt (Debian/Ubuntu):
sudo apt update
sudo apt install -y python3 python3-pip jq sysstat parallel pigz time
  • dnf (Fedora/RHEL):
sudo dnf install -y python3 python3-pip jq sysstat parallel pigz time
  • zypper (openSUSE):
sudo zypper refresh
sudo zypper install -y python3 python3-pip jq sysstat parallel pigz time

Python packages (user install; no root needed):

python3 -m pip install --user pandas scikit-learn optuna joblib

Add user-level scripts to your PATH if needed:

export PATH="$HOME/.local/bin:$PATH"

1) Instrument your Bash processes with lightweight metrics

Start capturing consistent metrics for every long-running command. Here’s a drop-in wrapper that logs elapsed time, CPU time, and max RSS (KB) as JSON Lines. It uses GNU time’s format to keep parsing simple.

Save as run_with_metrics.sh:

#!/usr/bin/env bash
set -euo pipefail

METRICS_FILE="${METRICS_FILE:-metrics.jsonl}"
TAG="${TAG:-}"
SIZE="${SIZE:-}"  # optional input size (bytes) if you know it

if [[ $# -lt 1 ]]; then
  echo "Usage: TAG=foo SIZE=1234 METRICS_FILE=metrics.jsonl $0 '<command>'" >&2
  exit 1
fi

CMD="$1"
TMP="$(mktemp)"
START_TS="$(date -Is)"

# Measure: elapsed (%e), user (%U), sys (%S), max RSS in KB (%M)
# Note: we capture exit code separately
set +e
/usr/bin/time -f "%e %U %S %M" -o "$TMP" bash -c "$CMD"
EXIT_CODE=$?
set -e

read -r ELAPSED USER_S SYS_S MAX_RSS_KB < "$TMP"
rm -f "$TMP"

# Build JSON line (avoid jq requirement for generation)
printf '{"ts":"%s","tag":"%s","cmd":%s,"elapsed":%s,"user_s":%s,"sys_s":%s,"max_rss_kb":%s,"exit":%d,"size":%s}\n' \
  "$START_TS" "$TAG" "$(printf %s "$CMD" | python3 -c 'import json,sys; print(json.dumps(sys.stdin.read()))')" \
  "$ELAPSED" "$USER_S" "$SYS_S" "$MAX_RSS_KB" "$EXIT_CODE" "${SIZE:-null}" >> "$METRICS_FILE"

exit "$EXIT_CODE"

Example usage:

# Compress a file and log metrics
TAG=compress SIZE=$(stat -c%s bigfile.dat) ./run_with_metrics.sh 'pigz -p 4 -9 -k bigfile.dat'

Optional: Sample per-second CPU and memory of a live PID with pidstat (from sysstat):

# Run a job in background, sample it for 10s
my_job &
PID=$!
pidstat -h -r -u -p "$PID" 1 10
wait "$PID"

Now you have a growing metrics.jsonl you can query with jq:

jq -r '[.tag,.elapsed,.max_rss_kb] | @tsv' metrics.jsonl | column -t

2) Catch regressions with a simple anomaly detector

Use your metrics to automatically flag “weird” runs (too slow, too memory-hungry) before they bite you in production.

Save as detect_anomalies.py:

#!/usr/bin/env python3
import sys, json
import pandas as pd
from sklearn.ensemble import IsolationForest

if len(sys.argv) < 2:
    print("Usage: detect_anomalies.py metrics.jsonl", file=sys.stderr)
    sys.exit(1)

df = pd.read_json(sys.argv[1], lines=True)

# Feature engineering
for c in ("elapsed","user_s","sys_s","max_rss_kb","size"):
    if c not in df.columns:
        df[c] = 0.0
X = df[["elapsed","user_s","sys_s","max_rss_kb","size"]].fillna(0)

# Train a quick unsupervised model
model = IsolationForest(n_estimators=200, contamination=0.05, random_state=42)
model.fit(X)
scores = model.decision_function(X)
pred = model.predict(X)  # -1 = anomaly

df["anomaly_score"] = scores
df["is_anomaly"] = (pred == -1)

anoms = df[df["is_anomaly"]].sort_values("anomaly_score")
cols = ["ts","tag","cmd","elapsed","max_rss_kb","anomaly_score"]
print(anoms[cols].to_string(index=False))

Run it:

python3 detect_anomalies.py metrics.jsonl

Schedule it in cron or CI to fail fast when a job regresses.


3) Predict runtimes to schedule smarter

If you know (or can infer) features like input size and thread count, you can learn a runtime predictor to:

  • Sort short jobs first to reduce tail latency

  • Balance long and short tasks across cores

  • Estimate SLA adherence before running

Train a regression model and save it:

Save as train_runtime_model.py:

#!/usr/bin/env python3
import sys
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestRegressor
from joblib import dump

if len(sys.argv) < 3:
    print("Usage: train_runtime_model.py metrics.jsonl model.joblib", file=sys.stderr)
    sys.exit(1)

df = pd.read_json(sys.argv[1], lines=True)
df = df[df["exit"] == 0]  # only successful runs

# Minimal features; add more from your domain (flags, data type, etc.)
for c in ("size","max_rss_kb","user_s","sys_s"):
    if c not in df: df[c] = 0.0
X = df[["size","max_rss_kb","user_s","sys_s"]].fillna(0)
y = df["elapsed"]

Xtr, Xte, ytr, yte = train_test_split(X, y, test_size=0.2, random_state=42)
model = RandomForestRegressor(n_estimators=300, random_state=42, n_jobs=-1)
model.fit(Xtr, ytr)

print("R^2 test:", model.score(Xte, yte))
dump(model, sys.argv[2])

Predict durations for upcoming tasks and schedule them:

Save as predict_and_schedule.py:

#!/usr/bin/env python3
import sys, json
import pandas as pd
from joblib import load
import subprocess, shlex

if len(sys.argv) < 3:
    print("Usage: predict_and_schedule.py model.joblib tasks.tsv", file=sys.stderr)
    print("tasks.tsv format: size<TAB>command", file=sys.stderr)
    sys.exit(1)

model = load(sys.argv[1])
tasks = pd.read_csv(sys.argv[2], sep="\t", names=["size","cmd"])
tasks["max_rss_kb"] = 0
tasks["user_s"] = 0
tasks["sys_s"] = 0

X = tasks[["size","max_rss_kb","user_s","sys_s"]]
tasks["pred_s"] = model.predict(X)

# Shortest-job-first as a simple heuristic to reduce makespan tail
tasks = tasks.sort_values("pred_s")

# Run in parallel across all cores; tag and log
commands = tasks["cmd"].tolist()
parallel = ["parallel","-j","0","--eta","--joblog","joblog.tsv","--tagstring","{=1 $_=q{} =}"]
subprocess.run(parallel + ["bash","-lc","{}"], input=("\n".join(commands)).encode(), check=True)

Example tasks file:

# tasks.tsv
104857600    pigz -p 4 -9 -k data/part-001
209715200    pigz -p 4 -9 -k data/part-002
...

This tiny loop—predict, sort, parallelize—often improves utilization and lowers total wall time without touching your core logic.


4) Auto-tune CLI parameters with Bayesian optimization

Stop guessing flags. Use search. Here we tune pigz’s thread count and compression level to minimize elapsed time while respecting a memory cap.

Save as tune_pigz.py:

#!/usr/bin/env python3
import os, sys, shlex, subprocess
import optuna

if len(sys.argv) < 3:
    print("Usage: tune_pigz.py INPUT_FILE N_TRIALS", file=sys.stderr)
    sys.exit(1)

INPUT = sys.argv[1]
N_TRIALS = int(sys.argv[2])
MEM_CAP_KB = int(os.environ.get("MEM_CAP_KB", "2097152"))  # 2 GiB default

def run_timed(cmd):
    # Capture elapsed secs (%e) and max RSS KB (%M)
    time_fmt = "%e %M"
    res = subprocess.run(
        ["/usr/bin/time","-f",time_fmt,"-o","/dev/stdout","bash","-lc",cmd],
        stdout=subprocess.PIPE, stderr=subprocess.STDOUT, check=True, text=True
    )
    elapsed, maxrss = res.stdout.strip().split()
    return float(elapsed), int(maxrss)

def objective(trial):
    threads = trial.suggest_int("threads", 1, max(1, os.cpu_count() or 1))
    level = trial.suggest_int("level", 1, 9)
    # Use -k to keep input; send output to /dev/null to avoid disk skew
    cmd = f"pigz -p {threads} -{level} -c {shlex.quote(INPUT)} > /dev/null"
    elapsed, maxrss = run_timed(cmd)
    # Penalize memory over cap
    penalty = 0.0 if maxrss <= MEM_CAP_KB else (maxrss - MEM_CAP_KB) / MEM_CAP_KB
    return elapsed * (1.0 + penalty)

study = optuna.create_study(direction="minimize")
study.optimize(objective, n_trials=N_TRIALS)

print("Best params:", study.best_params)
print("Best objective (sec):", study.best_value)

Run it:

# Optional: cap memory to 2 GiB
export MEM_CAP_KB=$((2*1024*1024))
python3 tune_pigz.py bigfile.dat 30

Use the best params in production, and re-tune when hardware or data patterns change.


5) A simple, real-world arc: compress faster, safer

  • Baseline:
TAG=compress_baseline SIZE=$(stat -c%s bigfile.dat) \
  ./run_with_metrics.sh 'pigz -p 4 -9 -k bigfile.dat'
  • Tune:
python3 tune_pigz.py bigfile.dat 30
# Suppose it suggests: -p 8 -7
  • Deploy tuned flags, keep logging:
TAG=compress_tuned SIZE=$(stat -c%s bigfile.dat) \
  ./run_with_metrics.sh 'pigz -p 8 -7 -k bigfile.dat'
  • Detect regressions automatically:
python3 detect_anomalies.py metrics.jsonl
  • Predict and schedule multiple files for nightly batch:
# Build tasks.tsv automatically
find data -type f -name 'part-*' -printf '%s\tpigz -p 8 -7 -k %p\n' > tasks.tsv
python3 train_runtime_model.py metrics.jsonl model.joblib
python3 predict_and_schedule.py model.joblib tasks.tsv

This loop gives you measurable speedups, fast feedback on regressions, and smarter use of cores.


Conclusion and next steps (CTA)

You don’t need a massive ML stack to optimize your shell workflows:

  • Start today by wrapping your long-running commands with run_with_metrics.sh.

  • Add a weekly or per-commit anomaly check to catch regressions early.

  • Train a simple runtime model and schedule jobs shortest-first for better utilization.

  • Replace flag guessing with a small tuning harness and re-run it when workloads shift.

Pick one pipeline this week, add metrics, and run the anomaly detector. Once you see the first “aha,” fold in prediction and tuning. Your Bash scripts will feel a lot faster—because they are.