Skip to content

Commit e550093

Browse files
authored
Merge pull request anthms#1 from anthms/copilot/setup-intermediate-scripting-repo
Bootstrap intermediate DevOps scripting study repo with Bash, Python, and GitHub Actions CI
2 parents 280be02 + 0f541b5 commit e550093

20 files changed

Lines changed: 1657 additions & 1 deletion

.github/workflows/ci.yml

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
name: CI
2+
3+
on:
4+
workflow_dispatch:
5+
6+
jobs:
7+
bash-tests:
8+
name: Bash Tests
9+
runs-on: ubuntu-latest
10+
permissions:
11+
contents: read
12+
steps:
13+
- uses: actions/checkout@v4
14+
15+
- name: Check Bash version
16+
run: bash --version
17+
18+
- name: Run Bash scripts (smoke test)
19+
run: |
20+
bash bash/basics/variables.sh
21+
bash bash/basics/loops.sh
22+
bash bash/basics/functions.sh
23+
bash bash/devops/file_operations.sh
24+
bash bash/devops/environment_check.sh
25+
26+
- name: Run Bash test suite
27+
run: bash bash/tests/run_tests.sh
28+
29+
python-tests:
30+
name: Python Tests
31+
runs-on: ubuntu-latest
32+
permissions:
33+
contents: read
34+
steps:
35+
- uses: actions/checkout@v4
36+
37+
- name: Set up Python
38+
uses: actions/setup-python@v5
39+
with:
40+
python-version: "3.12"
41+
42+
- name: Install dependencies
43+
run: pip install -r python/requirements.txt
44+
45+
- name: Run Python scripts (smoke test)
46+
run: |
47+
python python/basics/variables.py
48+
python python/basics/loops.py
49+
python python/basics/functions.py
50+
python python/devops/file_operations.py
51+
python python/devops/environment_check.py
52+
53+
- name: Run pytest
54+
working-directory: python
55+
run: pytest tests/ -v --tb=short

.gitignore

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# Python
2+
__pycache__/
3+
*.pyc
4+
*.pyo
5+
*.pyd
6+
.pytest_cache/
7+
.python-version
8+
*.egg-info/
9+
dist/
10+
build/
11+
.venv/
12+
venv/
13+
14+
# Editors
15+
.vscode/
16+
.idea/
17+
*.swp
18+
*.swo
19+
20+
# OS
21+
.DS_Store
22+
Thumbs.db

README.md

Lines changed: 68 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,68 @@
1-
# scripting-study
1+
# scripting-study
2+
3+
Intermediate scripting study repository focused on DevOps and CI/CD automation, covering both **Bash** and **Python**.
4+
5+
## Goals
6+
7+
- Learn and practice intermediate scripting patterns used in real DevOps workflows
8+
- Run and test scripts both **locally** and through **GitHub Actions** automation
9+
- Build reusable patterns for CI/CD pipelines, system management, and file operations
10+
11+
## Repository Structure
12+
13+
```
14+
scripting-study/
15+
├── bash/
16+
│ ├── basics/ # Intermediate Bash concepts (variables, loops, functions)
17+
│ ├── devops/ # DevOps-focused Bash scripts (files, env, processes)
18+
│ └── tests/ # Bash test runner and unit tests
19+
├── python/
20+
│ ├── basics/ # Intermediate Python concepts (variables, loops, functions)
21+
│ ├── devops/ # DevOps-focused Python scripts (files, env, processes)
22+
│ ├── tests/ # pytest test suite
23+
│ └── requirements.txt
24+
└── .github/
25+
└── workflows/
26+
└── ci.yml # GitHub Actions CI for both Bash and Python
27+
```
28+
29+
## Quick Start
30+
31+
### Bash
32+
33+
```bash
34+
# Run a script directly
35+
bash bash/basics/variables.sh
36+
37+
# Run the Bash test suite
38+
bash bash/tests/run_tests.sh
39+
```
40+
41+
### Python
42+
43+
```bash
44+
# Install dependencies
45+
pip install -r python/requirements.txt
46+
47+
# Run a script directly
48+
python python/basics/variables.py
49+
50+
# Run the Python test suite
51+
pytest python/tests/ -v
52+
```
53+
54+
## Topics Covered
55+
56+
| Topic | Bash | Python |
57+
|---|---|---|
58+
| Variables & data types |||
59+
| Loops & iteration |||
60+
| Functions |||
61+
| File operations |||
62+
| Environment & system info |||
63+
| CI/CD automation | ✅ (GitHub Actions) | ✅ (GitHub Actions) |
64+
65+
## CI / CD
66+
67+
All scripts are validated automatically on every push and pull request via **GitHub Actions**.
68+
See [`.github/workflows/ci.yml`](.github/workflows/ci.yml) for the workflow definition.

bash/basics/functions.sh

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
#!/usr/bin/env bash
2+
# Intermediate Bash: Functions, arguments, return values, and scope
3+
set -euo pipefail
4+
5+
# ── Basic function ────────────────────────────────────────────────────────────
6+
7+
greet() {
8+
local name="${1:-World}" # positional arg with default
9+
echo "Hello, ${name}!"
10+
}
11+
12+
greet
13+
greet "DevOps"
14+
15+
# ── Return values via stdout ──────────────────────────────────────────────────
16+
17+
to_upper() {
18+
echo "${1^^}"
19+
}
20+
21+
result=$(to_upper "hello")
22+
echo "Uppercase: $result"
23+
24+
# ── Return codes ──────────────────────────────────────────────────────────────
25+
26+
is_even() {
27+
(( $1 % 2 == 0 )) # returns 0 (true) if even, 1 (false) if odd
28+
}
29+
30+
for n in 3 4 7 8; do
31+
if is_even "$n"; then
32+
echo "$n is even"
33+
else
34+
echo "$n is odd"
35+
fi
36+
done
37+
38+
# ── Variadic functions ($@ and $*) ────────────────────────────────────────────
39+
40+
echo ""
41+
echo "=== variadic ==="
42+
43+
sum_all() {
44+
local total=0
45+
for num in "$@"; do
46+
((total += num))
47+
done
48+
echo "$total"
49+
}
50+
51+
echo "Sum 1 2 3 4 5 = $(sum_all 1 2 3 4 5)"
52+
53+
# ── Local vs global scope ─────────────────────────────────────────────────────
54+
55+
echo ""
56+
echo "=== scope ==="
57+
58+
GLOBAL_VAR="I am global"
59+
60+
demonstrate_scope() {
61+
local local_var="I am local"
62+
GLOBAL_VAR="modified by function"
63+
echo "Inside local_var : $local_var"
64+
echo "Inside GLOBAL_VAR: $GLOBAL_VAR"
65+
}
66+
67+
demonstrate_scope
68+
echo "Outside GLOBAL_VAR: $GLOBAL_VAR"
69+
# local_var is not accessible here
70+
71+
# ── Recursive function ────────────────────────────────────────────────────────
72+
73+
echo ""
74+
echo "=== recursion ==="
75+
76+
factorial() {
77+
local n=$1
78+
if [[ $n -le 1 ]]; then
79+
echo 1
80+
else
81+
local sub
82+
sub=$(factorial $((n - 1)))
83+
echo $((n * sub))
84+
fi
85+
}
86+
87+
echo "5! = $(factorial 5)"
88+
89+
# ── Function as error handler ─────────────────────────────────────────────────
90+
91+
echo ""
92+
echo "=== error handling ==="
93+
94+
die() {
95+
local msg="${1:-An error occurred}"
96+
local code="${2:-1}"
97+
echo "ERROR: $msg" >&2
98+
exit "$code"
99+
}
100+
101+
safe_divide() {
102+
local a=$1 b=$2
103+
if [[ $b -eq 0 ]]; then
104+
die "Division by zero" 1
105+
fi
106+
echo $((a / b))
107+
}
108+
109+
echo "10 / 2 = $(safe_divide 10 2)"
110+
# Uncommenting below would exit with an error:
111+
# safe_divide 5 0
112+
113+
# ── Passing arrays to functions (via nameref, Bash 4.3+) ─────────────────────
114+
115+
echo ""
116+
echo "=== nameref array param ==="
117+
118+
print_array() {
119+
local -n arr_ref=$1 # nameref to the caller's array
120+
for item in "${arr_ref[@]}"; do
121+
echo " - $item"
122+
done
123+
}
124+
125+
my_list=("ci" "cd" "devops" "automation")
126+
print_array my_list

bash/basics/loops.sh

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
#!/usr/bin/env bash
2+
# Intermediate Bash: Loops and iteration patterns
3+
set -euo pipefail
4+
5+
# ── C-style for loop ──────────────────────────────────────────────────────────
6+
7+
echo "=== C-style for loop ==="
8+
for ((i = 1; i <= 5; i++)); do
9+
printf " i = %d\n" "$i"
10+
done
11+
12+
# ── for-in over an array ──────────────────────────────────────────────────────
13+
14+
echo ""
15+
echo "=== for-in array ==="
16+
services=("nginx" "postgres" "redis" "app")
17+
for svc in "${services[@]}"; do
18+
printf " service: %s\n" "$svc"
19+
done
20+
21+
# ── Brace expansion range ─────────────────────────────────────────────────────
22+
23+
echo ""
24+
echo "=== brace expansion (01..05) ==="
25+
for n in {01..05}; do
26+
printf " item_%s\n" "$n"
27+
done
28+
29+
# ── while loop with counter ───────────────────────────────────────────────────
30+
31+
echo ""
32+
echo "=== while loop ==="
33+
attempt=1
34+
max=3
35+
while [[ $attempt -le $max ]]; do
36+
printf " attempt %d of %d\n" "$attempt" "$max"
37+
((attempt++))
38+
done
39+
40+
# ── until loop ────────────────────────────────────────────────────────────────
41+
42+
echo ""
43+
echo "=== until loop ==="
44+
count=0
45+
until [[ $count -ge 3 ]]; do
46+
printf " count = %d\n" "$count"
47+
(( ++count ))
48+
done
49+
50+
# ── Loop with break / continue ────────────────────────────────────────────────
51+
52+
echo ""
53+
echo "=== break and continue ==="
54+
for i in {1..10}; do
55+
if [[ $((i % 2)) -eq 0 ]]; then
56+
continue # skip even numbers
57+
fi
58+
if [[ $i -gt 7 ]]; then
59+
break # stop after 7
60+
fi
61+
printf " odd: %d\n" "$i"
62+
done
63+
64+
# ── Reading lines from a file / process substitution ─────────────────────────
65+
66+
echo ""
67+
echo "=== process substitution (read lines) ==="
68+
while IFS= read -r line; do
69+
printf " line: %s\n" "$line"
70+
done < <(printf "alpha\nbeta\ngamma\n")
71+
72+
# ── Iterating over command output with mapfile ────────────────────────────────
73+
74+
echo ""
75+
echo "=== mapfile (readarray) ==="
76+
mapfile -t words < <(printf "one\ntwo\nthree\n")
77+
for word in "${words[@]}"; do
78+
printf " word: %s\n" "$word"
79+
done
80+
81+
# ── Nested loops with labels (using functions) ────────────────────────────────
82+
83+
echo ""
84+
echo "=== nested loops ==="
85+
for row in 1 2 3; do
86+
for col in A B C; do
87+
printf " (%d,%s)" "$row" "$col"
88+
done
89+
echo ""
90+
done

0 commit comments

Comments
 (0)