💻 5.9 Identify Bash Script Workflows
Overview
Bash scripts automate repetitive system administration tasks. By reading a bash script, you can identify what workflow is being automated such as file management, application installation, user management, or directory navigation.
1. File Management Workflow
📁 Creating, Copying, Moving, and Deleting Files
Workflow Identification: Bash scripts that manage files and directories
#!/bin/bash
# File Management Script
# Create directory structure
echo "Creating directory structure..."
mkdir -p /var/backups/daily
mkdir -p /var/backups/weekly
mkdir -p /var/backups/monthly
# Copy configuration files
echo "Backing up configuration files..."
cp /etc/nginx/nginx.conf /var/backups/daily/nginx.conf.$(date +%Y%m%d)
cp /etc/mysql/my.cnf /var/backups/daily/mysql.conf.$(date +%Y%m%d)
# Move old logs to archive
echo "Archiving old logs..."
find /var/log/app -name "*.log" -mtime +7 -exec mv {} /var/backups/weekly/ \;
# Delete files older than 30 days
echo "Cleaning up old backups..."
find /var/backups/daily -mtime +30 -delete
# Set permissions
chmod 644 /var/backups/daily/*
chown root:root /var/backups/daily/*
# Create compressed archive
tar -czf /var/backups/monthly/config-$(date +%Y%m).tar.gz /etc/nginx /etc/mysql
echo "File management complete!"
# WORKFLOW IDENTIFIED:
# 1. Create directory structure with mkdir -p
# 2. Copy files with timestamp
# 3. Move old files to archive using find
# 4. Delete files older than 30 days
# 5. Set file permissions (chmod/chown)
# 6. Create compressed archivesCommon File Management Commands
| Command | Purpose | Example |
|---|---|---|
| cp | Copy files | cp file.txt backup/ |
| mv | Move/rename files | mv old.txt new.txt |
| rm | Remove files | rm -rf /tmp/old/ |
| mkdir | Create directories | mkdir -p /path/to/dir |
| chmod | Change permissions | chmod 755 script.sh |
| chown | Change ownership | chown user:group file |
2. Application Installation Workflow
📥 Installing and Configuring Applications
Workflow Identification: Scripts that download, install, and configure software
#!/bin/bash # Application Installation Script # Update package lists echo "Updating package lists..." apt-get update -y # Install prerequisites echo "Installing prerequisites..." apt-get install -y curl wget git build-essential # Download application echo "Downloading application..." cd /tmp wget https://example.com/app/releases/app-v1.2.3.tar.gz # Extract archive echo "Extracting application..." tar -xzf app-v1.2.3.tar.gz cd app-v1.2.3 # Compile and install echo "Compiling application..." ./configure --prefix=/usr/local make make install # Install Python dependencies echo "Installing Python dependencies..." pip3 install -r requirements.txt # Install Node.js application echo "Installing Node.js app..." npm install -g pm2 npm install --production # Create systemd service cat > /etc/systemd/system/myapp.service << EOF [Unit] Description=My Application After=network.target [Service] Type=simple User=www-data WorkingDirectory=/opt/myapp ExecStart=/usr/bin/node /opt/myapp/server.js Restart=always [Install] WantedBy=multi-user.target EOF # Enable and start service systemctl daemon-reload systemctl enable myapp systemctl start myapp echo "Application installed successfully!" # WORKFLOW IDENTIFIED: # 1. Update system packages (apt-get update) # 2. Install prerequisites # 3. Download application (wget/curl) # 4. Extract archive (tar) # 5. Compile from source (./configure, make) # 6. Install dependencies (pip, npm) # 7. Create systemd service # 8. Enable and start service
Installation Commands
| Command | Purpose | Package Manager |
|---|---|---|
| apt-get install | Install packages | Debian/Ubuntu |
| yum install | Install packages | RHEL/CentOS |
| dnf install | Install packages | Fedora/RHEL 8+ |
| wget/curl | Download files | HTTP/FTP |
| tar | Extract archives | Compression |
| pip/npm | Language packages | Python/Node.js |
3. User Management Workflow
👥 Creating and Managing Users
Workflow Identification: Scripts that create, modify, or delete user accounts
#!/bin/bash
# User Management Script
# Create new user
echo "Creating user..."
useradd -m -s /bin/bash -c "Application User" appuser
# Set password
echo "appuser:SecureP@ss123" | chpasswd
# Create additional users from list
USERS=("devuser1" "devuser2" "devuser3")
for user in "${USERS[@]}"; do
useradd -m -s /bin/bash "$user"
echo "Created user: $user"
done
# Add user to groups
usermod -aG sudo,docker appuser
# Create SSH directory and set permissions
mkdir -p /home/appuser/.ssh
chmod 700 /home/appuser/.ssh
# Add SSH public key
cat > /home/appuser/.ssh/authorized_keys << EOF
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABg... user@hostname
EOF
chmod 600 /home/appuser/.ssh/authorized_keys
chown -R appuser:appuser /home/appuser/.ssh
# Modify existing user
usermod -s /bin/zsh devuser1
usermod -d /opt/devuser1 -m devuser1
# Lock/unlock user accounts
usermod -L tempuser # Lock account
usermod -U tempuser # Unlock account
# Delete user
userdel -r olduser # Remove user and home directory
# Set password expiration
chage -M 90 appuser # Password expires in 90 days
chage -l appuser # List password aging information
echo "User management complete!"
# WORKFLOW IDENTIFIED:
# 1. Create users with useradd
# 2. Set passwords with chpasswd
# 3. Add users to groups with usermod -aG
# 4. Configure SSH keys
# 5. Modify user properties (shell, home directory)
# 6. Lock/unlock accounts
# 7. Delete users with userdelUser Management Commands
| Command | Purpose | Example |
|---|---|---|
| useradd | Create user | useradd -m username |
| usermod | Modify user | usermod -aG group user |
| userdel | Delete user | userdel -r username |
| passwd | Set password | passwd username |
| chage | Password aging | chage -M 90 user |
| groups | Show user groups | groups username |
4. Directory Navigation Workflow
🧭 Navigating and Searching Directories
Workflow Identification: Scripts that navigate filesystem and find files
#!/bin/bash
# Directory Navigation Script
# Store current directory
CURRENT_DIR=$(pwd)
echo "Starting from: $CURRENT_DIR"
# Change to home directory
cd ~
echo "Home directory: $(pwd)"
# Change to specific directory
cd /var/log || exit 1
# Go up one directory
cd ..
echo "Parent directory: $(pwd)"
# Go back to previous directory
cd -
# Find files by name
echo "Finding log files..."
find /var/log -name "*.log" -type f
# Find files modified in last 7 days
find /var/log -mtime -7 -type f
# Find and execute command on files
find /tmp -name "*.tmp" -mtime +30 -exec rm -f {} \;
# Find large files (>100MB)
find /home -size +100M -type f
# Locate command (faster search)
locate nginx.conf
# Update locate database
updatedb
# Search in multiple directories
for dir in /etc /var /opt; do
if [ -d "$dir" ]; then
echo "Searching in $dir..."
find "$dir" -name "config.*" -type f 2>/dev/null
fi
done
# Create directory path if it doesn't exist
mkdir -p /opt/myapp/config/production
mkdir -p /opt/myapp/logs
mkdir -p /opt/myapp/data
# Navigate and create project structure
cd /opt/myapp
mkdir -p {bin,lib,config,logs,data,tmp}
# Return to original directory
cd "$CURRENT_DIR"
echo "Directory navigation complete!"
# WORKFLOW IDENTIFIED:
# 1. Navigate directories (cd, pwd)
# 2. Find files by criteria (find command)
# 3. Search for files (locate)
# 4. Create directory structures (mkdir -p)
# 5. Execute commands on found files
# 6. Store and return to directoriesNavigation Commands
| Command | Purpose | Example |
|---|---|---|
| cd | Change directory | cd /var/log |
| pwd | Print working directory | pwd |
| find | Search for files | find / -name "*.conf" |
| locate | Fast file search | locate filename |
| ls | List directory contents | ls -lah |
| tree | Display directory tree | tree -L 2 /etc |
🔍 5.10 Interpret RESTCONF/NETCONF Query Results
Overview
RESTCONF and NETCONF queries return structured data (JSON/XML) that represents device configuration and operational state. Interpreting these results requires understanding the data format, hierarchy, and meaning of each field.
HTTP GET"] A --> C["NETCONF
RPC Request"] B --> D["JSON/XML Response"] C --> D D --> E["Parse Data"] E --> F["Interpret Structure"] F --> G["Extract Values"] style A fill:#667eea,stroke:#764ba2,stroke-width:3px,color:#fff style B fill:#66bb6a,stroke:#2e7d32,stroke-width:2px,color:#fff style C fill:#42a5f5,stroke:#1976d2,stroke-width:2px,color:#fff style G fill:#ffa726,stroke:#e65100,stroke-width:2px,color:#fff
1. RESTCONF JSON Response - Interfaces
📄 Interpreting Interface Configuration (JSON)
Query: GET /restconf/data/ietf-interfaces:interfaces
{
"ietf-interfaces:interfaces": {
"interface": [
{
"name": "GigabitEthernet1",
"description": "WAN Interface to ISP",
"type": "iana-if-type:ethernetCsmacd",
"enabled": true,
"ietf-ip:ipv4": {
"address": [
{
"ip": "203.0.113.1",
"netmask": "255.255.255.252"
}
]
},
"ietf-ip:ipv6": {
"enabled": false
}
},
{
"name": "GigabitEthernet2",
"description": "LAN Interface",
"type": "iana-if-type:ethernetCsmacd",
"enabled": true,
"ietf-ip:ipv4": {
"address": [
{
"ip": "192.168.1.1",
"netmask": "255.255.255.0"
}
]
}
}
]
}
}
# INTERPRETATION:
# - Root: ietf-interfaces:interfaces container
# - Two interfaces configured: GigabitEthernet1 and GigabitEthernet2
# - GigabitEthernet1:
# * Public IP: 203.0.113.1/30 (WAN connection)
# * Description indicates ISP connection
# * Interface is enabled (operational)
# * IPv6 is disabled
# - GigabitEthernet2:
# * Private IP: 192.168.1.1/24 (LAN connection)
# * Interface is enabled
# * Likely serves as default gateway for internal networkKey Fields Explained
| Field | Meaning |
|---|---|
| name | Interface identifier (e.g., GigabitEthernet1) |
| description | Human-readable interface purpose |
| type | Interface type (Ethernet, Serial, Loopback, etc.) |
| enabled | Administrative status (true=up, false=down) |
| ipv4/ipv6 | IP address configuration and settings |
2. NETCONF XML Response - Configuration
📜 Interpreting Device Configuration (XML)
Query: NETCONF <get-config> operation
<?xml version="1.0" encoding="UTF-8"?>
<rpc-reply xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"
message-id="101">
<data>
<interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces">
<interface>
<name>GigabitEthernet1</name>
<description>Management Interface</description>
<type>ianaift:ethernetCsmacd</type>
<enabled>true</enabled>
<ipv4 xmlns="urn:ietf:params:xml:ns:yang:ietf-ip">
<address>
<ip>10.10.10.1</ip>
<netmask>255.255.255.0</netmask>
</address>
</ipv4>
</interface>
</interfaces>
<routing xmlns="urn:ietf:params:xml:ns:yang:ietf-routing">
<routing-instance>
<name>default</name>
<type>rt:default-routing-instance</type>
<router-id>10.10.10.1</router-id>
<routing-protocols>
<routing-protocol>
<type>rt:ospf</type>
<name>ospf-1</name>
</routing-protocol>
</routing-protocols>
</routing-instance>
</routing>
</data>
</rpc-reply>
# INTERPRETATION:
# - RPC Reply to message-id 101 (successful response)
# - Interface Configuration:
# * GigabitEthernet1 configured as Management Interface
# * IP address: 10.10.10.1/24
# * Interface is administratively up (enabled: true)
# * Type: Ethernet interface
# - Routing Configuration:
# * Default routing instance active
# * Router ID: 10.10.10.1
# * OSPF protocol enabled (ospf-1)
# * Using default VRFXML Structure Elements
| Element | Purpose |
|---|---|
| <rpc-reply> | Root element for NETCONF response |
| <data> | Contains configuration/operational data |
| xmlns | XML namespace (identifies YANG model) |
| message-id | Matches request with response |
| Nested elements | Hierarchical data structure |
3. Operational State Data (RESTCONF)
📊 Interpreting Live Device Statistics
Query: GET /restconf/data/ietf-interfaces:interfaces-state
{
"ietf-interfaces:interfaces-state": {
"interface": [
{
"name": "GigabitEthernet1",
"type": "iana-if-type:ethernetCsmacd",
"admin-status": "up",
"oper-status": "up",
"if-index": 1,
"phys-address": "00:1a:2b:3c:4d:5e",
"speed": 1000000000,
"statistics": {
"in-octets": 1234567890,
"in-unicast-pkts": 9876543,
"in-errors": 0,
"in-discards": 0,
"out-octets": 9876543210,
"out-unicast-pkts": 8765432,
"out-errors": 0,
"out-discards": 2
}
}
]
}
}
# INTERPRETATION:
# Interface Status:
# * Administrative status: UP (enabled by administrator)
# * Operational status: UP (physically connected and working)
# * Speed: 1 Gbps (1000000000 bits/second)
# * MAC Address: 00:1a:2b:3c:4d:5e
#
# Traffic Statistics:
# * Received: ~1.23 GB (1,234,567,890 octets)
# * Received packets: 9,876,543 unicast packets
# * No input errors or discards (healthy)
# * Transmitted: ~9.87 GB (9,876,543,210 octets)
# * Transmitted packets: 8,765,432
# * No output errors, 2 discarded packets (minimal)
#
# Health Assessment: Interface is healthy and operationalStatus Values
| Field | Possible Values | Meaning |
|---|---|---|
| admin-status | up, down, testing | Administratively configured state |
| oper-status | up, down, testing, unknown | Current operational state |
| in-errors | integer | Count of inbound errors (CRC, etc.) |
| in-discards | integer | Packets discarded (buffer full, etc.) |
4. Error Response Interpretation
⚠️ Understanding Error Messages
Example 1: NETCONF Error Response
<rpc-reply xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"
message-id="102">
<rpc-error>
<error-type>protocol</error-type>
<error-tag>invalid-value</error-tag>
<error-severity>error</error-severity>
<error-message>
Invalid IP address format: 192.168.1.256
</error-message>
<error-info>
<bad-element>ip</bad-element>
</error-info>
</rpc-error>
</rpc-reply>
# INTERPRETATION:
# - Error Type: protocol (validation error)
# - Error Tag: invalid-value (data doesn't meet constraints)
# - Severity: error (operation failed)
# - Message: IP address 192.168.1.256 is invalid (octet > 255)
# - Bad Element: "ip" field contains the error
#
# Action Required: Correct IP address to valid format (0-255 per octet)Example 2: RESTCONF HTTP Error
HTTP/1.1 404 Not Found
Content-Type: application/yang-data+json
{
"ietf-restconf:errors": {
"error": [
{
"error-type": "application",
"error-tag": "invalid-value",
"error-path": "/ietf-interfaces:interfaces/interface[name='GigabitEthernet99']",
"error-message": "Interface GigabitEthernet99 does not exist"
}
]
}
}
# INTERPRETATION:
# - HTTP Status: 404 Not Found
# - Error Type: application (resource doesn't exist)
# - Error Tag: invalid-value
# - Error Path: Shows exact location in YANG tree
# - Message: Interface GigabitEthernet99 doesn't exist on device
#
# Action Required: Verify interface name or check available interfaces firstCommon Error Types
| Error Type | Meaning | Common Causes |
|---|---|---|
| protocol | Protocol layer error | Invalid XML/JSON, malformed request |
| application | Application layer error | Resource not found, access denied |
| rpc | RPC layer error | Operation not supported |
| transport | Transport layer error | Connection issues, timeouts |
📐 5.11 Interpret Basic YANG Models
Overview
YANG (Yet Another Next Generation) is a data modeling language used to model configuration and state data. Reading YANG models helps understand the structure, data types, and constraints of network device configurations accessible via NETCONF/RESTCONF.
1. Basic YANG Module Structure
📄 Understanding YANG Module Components
Example: Basic interface YANG model
---
- name: Package Management Workflow
hosts: webservers
become: yes
tasks:
# Install multiple packages
- name: Install Apache and PHP
apt:
name:
- apache2
- php
- php-mysql
state: present
update_cache: yes
# Update specific package
- name: Ensure Git is latest version
apt:
name: git
state: latest
# Remove unwanted package
- name: Remove telnet
apt:
name: telnet
state: absent
# WORKFLOW IDENTIFIED:
# 1. Install multiple packages (apache2, php, php-mysql)
# 2. Update existing package to latest version (git)
# 3. Remove security risk package (telnet)
# 4. Update package cache before installingKey Package Modules
- apt: Debian/Ubuntu package management
- yum/dnf: RHEL/CentOS package management
- package: Generic package manager
- pip: Python package installation
2. User Management Workflow
👥 Creating, Modifying, and Managing Users
Workflow Identification: User account lifecycle management and access control
---
- name: User Management Workflow
hosts: all
become: yes
tasks:
# Create new user with specific settings
- name: Create application user
user:
name: appuser
comment: "Application Service Account"
uid: 5000
group: appgroup
groups: docker,sudo
shell: /bin/bash
create_home: yes
state: present
# Add SSH key for user
- name: Add SSH key for appuser
authorized_key:
user: appuser
key: "{{ lookup('file', 'files/appuser_key.pub') }}"
state: present
# Modify existing user
- name: Update user shell
user:
name: devuser
shell: /bin/zsh
# Remove user
- name: Remove temporary user
user:
name: tempuser
state: absent
remove: yes
# WORKFLOW IDENTIFIED:
# 1. Create new user with UID, groups, and home directory
# 2. Configure SSH key authentication
# 3. Modify existing user properties
# 4. Remove user and associated filesUser Management Modules
- user: Create, modify, delete user accounts
- group: Manage user groups
- authorized_key: Manage SSH authorized keys
- lineinfile: Modify configuration files (sudoers, etc.)
3. Service Configuration Workflow
⚙️ Deploying and Configuring Services
Workflow Identification: Service deployment with configuration file management
---
- name: Service Configuration Workflow
hosts: webservers
become: yes
tasks:
# Copy configuration file
- name: Deploy Nginx configuration
copy:
src: files/nginx.conf
dest: /etc/nginx/nginx.conf
owner: root
group: root
mode: '0644'
backup: yes
notify: Restart Nginx
# Use template for dynamic config
- name: Deploy Apache vhost from template
template:
src: templates/vhost.conf.j2
dest: /etc/apache2/sites-available/{{ domain }}.conf
owner: root
group: root
mode: '0644'
vars:
domain: example.com
doc_root: /var/www/example
# Modify configuration file
- name: Set max_connections in MySQL
lineinfile:
path: /etc/mysql/my.cnf
regexp: '^max_connections'
line: 'max_connections = 500'
backup: yes
notify: Restart MySQL
handlers:
- name: Restart Nginx
service:
name: nginx
state: restarted
- name: Restart MySQL
service:
name: mysql
state: restarted
# WORKFLOW IDENTIFIED:
# 1. Deploy static configuration files
# 2. Generate configuration from templates
# 3. Modify existing configuration values
# 4. Trigger service restart when config changesConfiguration Modules
- copy: Copy files from controller to hosts
- template: Deploy Jinja2 templates with variables
- lineinfile: Modify single lines in files
- blockinfile: Insert/update/remove text blocks
4. Service Start/Stop Workflow
🔄 Service Lifecycle Management
Workflow Identification: Starting, stopping, restarting, and enabling services
---
- name: Service Lifecycle Workflow
hosts: all
become: yes
tasks:
# Start service
- name: Start Apache service
service:
name: apache2
state: started
# Stop service
- name: Stop old application service
service:
name: legacy-app
state: stopped
# Restart service
- name: Restart Nginx after config change
service:
name: nginx
state: restarted
# Reload service (graceful restart)
- name: Reload Apache configuration
service:
name: apache2
state: reloaded
# Enable service at boot
- name: Enable Docker service
service:
name: docker
enabled: yes
state: started
# Disable service at boot
- name: Disable unnecessary service
service:
name: bluetooth
enabled: no
state: stopped
# WORKFLOW IDENTIFIED:
# 1. Start services that should be running
# 2. Stop services that should not be running
# 3. Restart services after configuration changes
# 4. Enable/disable services at system boot
# 5. Use reload for graceful restartsService States
- started: Ensure service is running
- stopped: Ensure service is not running
- restarted: Stop and start service
- reloaded: Reload configuration without stopping
- enabled: Start service at boot
- disabled: Don't start service at boot
Complete Ansible Workflow Example
🎯 Combined Workflow: Web Server Deployment
Workflow Identification: Complete server setup combining all four workflow types
---
- name: Complete Web Server Deployment
hosts: webservers
become: yes
tasks:
# 1. PACKAGE MANAGEMENT
- name: Install required packages
apt:
name:
- nginx
- php-fpm
- git
state: present
update_cache: yes
# 2. USER MANAGEMENT
- name: Create web application user
user:
name: webapp
comment: "Web Application User"
shell: /bin/bash
create_home: yes
- name: Add webapp user to www-data group
user:
name: webapp
groups: www-data
append: yes
# 3. SERVICE CONFIGURATION
- name: Deploy Nginx configuration
template:
src: templates/nginx-site.conf.j2
dest: /etc/nginx/sites-available/webapp.conf
owner: root
group: root
mode: '0644'
notify: Reload Nginx
- name: Enable Nginx site
file:
src: /etc/nginx/sites-available/webapp.conf
dest: /etc/nginx/sites-enabled/webapp.conf
state: link
notify: Reload Nginx
# 4. SERVICE START/STOP
- name: Ensure Nginx is running and enabled
service:
name: nginx
state: started
enabled: yes
- name: Ensure PHP-FPM is running
service:
name: php7.4-fpm
state: started
enabled: yes
handlers:
- name: Reload Nginx
service:
name: nginx
state: reloaded
# COMPLETE WORKFLOW IDENTIFIED:
# 1. Install web server packages (nginx, php-fpm, git)
# 2. Create dedicated application user and add to groups
# 3. Deploy configuration files from templates
# 4. Enable site and create symlinks
# 5. Start and enable services at boot
# 6. Define handlers for graceful service reloads🐍 Interactive Python Interpreter
- Write Python code in the editor
- Click "▶ Run Code" to execute
- Try sample code buttons