Introduction
Ansible is a powerful open-source automation tool widely used by system administrators and DevOps professionals. One of its key capabilities is running shell commands on remote hosts and processing their output. In this hands-on tutorial, you will learn how to effectively capture, display, and process the output of shell commands in Ansible playbooks. This skill is essential for creating robust automation workflows that can adapt to different system conditions and provide useful feedback.
Setting Up Your First Ansible Playbook with Shell Commands
In this step, we will set up a basic Ansible playbook that executes shell commands and captures their output. This will provide the foundation for more advanced techniques in later steps.
Installing Ansible
First, let's install Ansible on our system:
sudo apt update
sudo apt install -y ansible
Now, verify that Ansible is installed correctly:
ansible --version
You should see output similar to this:
ansible [core 2.12.x]
config file = /etc/ansible/ansible.cfg
configured module search path = ['/home/labex/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
ansible python module location = /usr/lib/python3/dist-packages/ansible
ansible collection location = /home/labex/.ansible/collections:/usr/share/ansible/collections
executable location = /usr/bin/ansible
python version = 3.10.x (default, Mar 15 2022, 12:22:08) [GCC 11.2.0]
jinja version = 3.0.3
libyaml = True
Creating an Inventory File
Ansible uses an inventory file to know which hosts to manage. For this lab, we'll create a simple inventory that includes only the local machine:
- Open your WebIDE and create a new file called
inventory.iniin the/home/labex/projectdirectory. - Add the following content to the file:
[local]
localhost ansible_connection=local
This inventory defines a group called local that contains just the localhost, and tells Ansible to connect directly without SSH.
Creating Your First Playbook
Now, let's create a simple playbook that executes shell commands:
- Create a new file called
first_playbook.ymlin the/home/labex/projectdirectory. - Add the following YAML content to the file:
---
- name: Shell Command Example
hosts: local
gather_facts: no
tasks:
- name: Run a simple shell command
shell: echo "Hello from Ansible shell command"
register: hello_output
- name: Display the output
debug:
msg: "{{ hello_output.stdout }}"
This playbook does the following:
- Targets the
localgroup we defined in our inventory - Skips gathering facts (system information) to keep things simple
- Runs a shell command that echoes a greeting message
- Stores the output in a variable using the
registerkeyword - Displays the output using the
debugmodule
Running Your Playbook
Now let's run the playbook:
ansible-playbook -i inventory.ini first_playbook.yml
You should see output similar to this:
PLAY [Shell Command Example] **************************************************
TASK [Run a simple shell command] *********************************************
changed: [localhost]
TASK [Display the output] *****************************************************
ok: [localhost] => {
"msg": "Hello from Ansible shell command"
}
PLAY RECAP ********************************************************************
localhost : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
The output shows that our playbook ran successfully, executing the shell command and displaying its output.
Key Concepts to Understand
From this exercise, note these important concepts:
- The
shellmodule allows you to run shell commands - The
registerdirective captures the output of a task into a variable - The
debugmodule helps display variable values - Shell command output contains both
stdout(standard output) andstderr(error output)
In the next step, we'll explore how to process and format shell command output more effectively.
Working with Structured Shell Command Output
Now that you understand the basics of executing shell commands in Ansible, let's explore how to work with structured command output and display it in different formats.
Processing System Information
Let's create a more practical playbook that gathers system information and presents it in a structured way:
- Create a new file called
system_info.ymlin the/home/labex/projectdirectory. - Add the following content:
---
- name: Gather and Display System Information
hosts: local
gather_facts: no
tasks:
- name: Gather system information
shell: |
echo "OS Information: $(cat /etc/os-release | grep PRETTY_NAME | cut -d= -f2)"
echo "Kernel Version: $(uname -r)"
echo "CPU Information: $(grep "model name" /proc/cpuinfo | head -1 | cut -d: -f2 | xargs)"
echo "Memory Information: $(free -h | grep Mem | awk '{print $2}')"
register: system_info
- name: Display raw system information
debug:
msg: "{{ system_info.stdout }}"
- name: Display information as a list
debug:
msg: "{{ system_info.stdout_lines }}"
This playbook:
- Executes a multi-line shell script that gathers various system details
- Stores the output in the
system_infovariable - Displays the output first as a raw string and then as a list of lines
Run the playbook:
ansible-playbook -i inventory.ini system_info.yml
You should see output that looks like this:
PLAY [Gather and Display System Information] **********************************
TASK [Gather system information] **********************************************
changed: [localhost]
TASK [Display raw system information] *****************************************
ok: [localhost] => {
"msg": "OS Information: \"Ubuntu 22.04.1 LTS\"\nKernel Version: 5.15.0-1023-azure\nCPU Information: Intel(R) Xeon(R) Platinum 8171M CPU @ 2.60GHz\nMemory Information: 4.0Gi"
}
TASK [Display information as a list] *****************************************
ok: [localhost] => {
"msg": [
"OS Information: \"Ubuntu 22.04.1 LTS\"",
"Kernel Version: 5.15.0-1023-azure",
"CPU Information: Intel(R) Xeon(R) Platinum 8171M CPU @ 2.60GHz",
"Memory Information: 4.0Gi"
]
}
PLAY RECAP ********************************************************************
localhost : ok=3 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Notice how the second display task shows the output as a list instead of a string with newlines. This list format makes it easier to work with multi-line output.
Working with Command Results and Return Codes
Shell commands in Linux return exit codes to indicate success (0) or failure (non-zero). Ansible captures these in the rc (return code) attribute of the registered variable.
Let's create a playbook that demonstrates how to work with return codes:
- Create a new file called
command_results.ymlin the/home/labex/projectdirectory. - Add the following content:
---
- name: Working with Command Results
hosts: local
gather_facts: no
tasks:
- name: Check if a file exists
shell: test -f /etc/hosts
register: file_check
ignore_errors: yes
- name: Show command result details
debug:
msg: |
Return code: {{ file_check.rc }}
Succeeded: {{ file_check.rc == 0 }}
Failed: {{ file_check.rc != 0 }}
- name: Check if a non-existent file exists
shell: test -f /file/does/not/exist
register: missing_file
ignore_errors: yes
- name: Show command result for missing file
debug:
msg: |
Return code: {{ missing_file.rc }}
Succeeded: {{ missing_file.rc == 0 }}
Failed: {{ missing_file.rc != 0 }}
This playbook:
- Runs two test commands to check if files exist
- Uses
ignore_errors: yesto prevent the playbook from stopping if a command fails - Displays detailed command result information, including the return code and success/failure status
Run the playbook:
ansible-playbook -i inventory.ini command_results.yml
You should see output similar to this:
PLAY [Working with Command Results] *******************************************
TASK [Check if a file exists] *************************************************
changed: [localhost]
TASK [Show command result details] ********************************************
ok: [localhost] => {
"msg": "Return code: 0\nSucceeded: True\nFailed: False\n"
}
TASK [Check if a non-existent file exists] ************************************
fatal: [localhost]: FAILED! => {"changed": true, "cmd": "test -f /file/does/not/exist", "delta": "0:00:00.003183", "end": "2023-07-14 15:24:33.931406", "msg": "non-zero return code", "rc": 1, "start": "2023-07-14 15:24:33.928223", "stderr": "", "stderr_lines": [], "stdout": "", "stdout_lines": []}
...ignoring
TASK [Show command result for missing file] ***********************************
ok: [localhost] => {
"msg": "Return code: 1\nSucceeded: False\nFailed: True\n"
}
PLAY RECAP ********************************************************************
localhost : ok=4 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=1
Notice how the return code is 0 for the existing file and 1 for the non-existent file. This demonstrates how you can use return codes to make decisions in your playbooks.
Understanding The Registered Variable Structure
The variable registered from a shell command contains several useful attributes:
stdout: The standard output as a single stringstdout_lines: The standard output split into a list of linesstderr: The standard error output as a single stringstderr_lines: The standard error output split into a list of linesrc: The return code (0 for success, non-zero for failure)cmd: The command that was executedstartandend: Timestamps for when the command started and finisheddelta: The duration of the command execution
Understanding this structure is crucial for effectively working with shell command output in Ansible.
Conditional Execution Based on Shell Output
One of the most powerful capabilities in Ansible is the ability to make decisions based on the output of shell commands. In this step, we'll learn how to use conditions and filters to process shell command output and make playbooks more dynamic.
Using Conditions with Shell Output
Let's create a playbook that makes decisions based on shell command output:
- Create a new file called
conditional_playbook.ymlin the/home/labex/projectdirectory. - Add the following content:
---
- name: Conditional Tasks Based on Command Output
hosts: local
gather_facts: no
tasks:
- name: Check disk space
shell: df -h / | grep -v Filesystem | awk '{print $5}' | sed 's/%//'
register: disk_usage
- name: Display disk usage
debug:
msg: "Current disk usage: {{ disk_usage.stdout }}%"
- name: Disk usage warning
debug:
msg: "WARNING: Disk usage is high"
when: disk_usage.stdout|int > 50
- name: Disk usage normal
debug:
msg: "Disk usage is normal"
when: disk_usage.stdout|int <= 50
This playbook:
- Runs a shell command to check disk usage percentage on the root filesystem
- Uses the
whenconditional based on the command output - Uses the
intfilter to convert the string output to an integer for comparison
Run the playbook:
ansible-playbook -i inventory.ini conditional_playbook.yml
The output will vary depending on your actual disk usage, but will look something like this:
PLAY [Conditional Tasks Based on Command Output] ******************************
TASK [Check disk space] *******************************************************
changed: [localhost]
TASK [Display disk usage] *****************************************************
ok: [localhost] => {
"msg": "Current disk usage: 38%"
}
TASK [Disk usage warning] *****************************************************
skipped: [localhost]
TASK [Disk usage normal] ******************************************************
ok: [localhost] => {
"msg": "Disk usage is normal"
}
PLAY RECAP ********************************************************************
localhost : ok=3 changed=1 unreachable=0 failed=0 skipped=1 rescued=0 ignored=0
Notice how Ansible executed only one of the conditional tasks based on the actual disk usage value.
Handling JSON Output from Commands
Many modern CLI tools return data in JSON format. Ansible has built-in capabilities to handle JSON output:
- Create a new file called
json_output.ymlin the/home/labex/projectdirectory. - Add the following content:
---
- name: Handling JSON Output
hosts: local
gather_facts: no
tasks:
- name: Create a JSON file for testing
copy:
dest: /tmp/services.json
content: |
{
"services": [
{
"name": "web",
"status": "running",
"port": 80
},
{
"name": "database",
"status": "stopped",
"port": 5432
},
{
"name": "cache",
"status": "running",
"port": 6379
}
]
}
- name: Read JSON file with shell
shell: cat /tmp/services.json
register: json_output
- name: Parse and display JSON content
debug:
msg: "{{ json_output.stdout | from_json }}"
- name: Extract and display service information
debug:
msg: "Service: {{ item.name }}, Status: {{ item.status }}, Port: {{ item.port }}"
loop: "{{ (json_output.stdout | from_json).services }}"
- name: Show only running services
debug:
msg: "Running service: {{ item.name }} on port {{ item.port }}"
loop: "{{ (json_output.stdout | from_json).services }}"
when: item.status == "running"
This playbook:
- Creates a sample JSON file for demonstration
- Reads the JSON file with a shell command
- Uses the
from_jsonfilter to parse the JSON string into a data structure - Loops through the data structure to display information
- Uses conditional logic to filter only running services
Run the playbook:
ansible-playbook -i inventory.ini json_output.yml
You should see output similar to this:
PLAY [Handling JSON Output] ***************************************************
TASK [Create a JSON file for testing] *****************************************
changed: [localhost]
TASK [Read JSON file with shell] **********************************************
changed: [localhost]
TASK [Parse and display JSON content] *****************************************
ok: [localhost] => {
"msg": {
"services": [
{
"name": "web",
"port": 80,
"status": "running"
},
{
"name": "database",
"port": 5432,
"status": "stopped"
},
{
"name": "cache",
"port": 6379,
"status": "running"
}
]
}
}
TASK [Extract and display service information] ********************************
ok: [localhost] => (item={'name': 'web', 'status': 'running', 'port': 80}) => {
"msg": "Service: web, Status: running, Port: 80"
}
ok: [localhost] => (item={'name': 'database', 'status': 'stopped', 'port': 5432}) => {
"msg": "Service: database, Status: stopped, Port: 5432"
}
ok: [localhost] => (item={'name': 'cache', 'status': 'running', 'port': 6379}) => {
"msg": "Service: cache, Status: running, Port: 6379"
}
TASK [Show only running services] *********************************************
ok: [localhost] => (item={'name': 'web', 'status': 'running', 'port': 80}) => {
"msg": "Running service: web on port 80"
}
skipped: [localhost] => (item={'name': 'database', 'status': 'stopped', 'port': 5432})
ok: [localhost] => (item={'name': 'cache', 'status': 'running', 'port': 6379}) => {
"msg": "Running service: cache on port 6379"
}
PLAY RECAP ********************************************************************
localhost : ok=5 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Notice how the playbook parses the JSON, extracts specific information, and filters the data based on conditions.
Error Handling with Shell Commands
When running shell commands, it's important to handle potential errors gracefully:
- Create a new file called
error_handling.ymlin the/home/labex/projectdirectory. - Add the following content:
---
- name: Error Handling with Shell Commands
hosts: local
gather_facts: no
tasks:
- name: Run a potentially failing command
shell: grep "nonexistent_pattern" /etc/passwd
register: command_result
ignore_errors: yes
- name: Display success or failure
debug:
msg: "Command {{ 'succeeded' if command_result.rc == 0 else 'failed with return code ' + command_result.rc|string }}"
- name: Run a custom failing command
shell: exit 3
register: exit_command
ignore_errors: yes
- name: Display detailed error information
debug:
msg: |
Return code: {{ exit_command.rc }}
Error message: {{ exit_command.stderr if exit_command.stderr else 'No error message' }}
This playbook:
- Runs commands that are expected to fail
- Uses
ignore_errors: yesto continue the playbook execution even when commands fail - Shows different methods for handling and displaying error information
Run the playbook:
ansible-playbook -i inventory.ini error_handling.yml
You should see output similar to this:
PLAY [Error Handling with Shell Commands] *************************************
TASK [Run a potentially failing command] **************************************
fatal: [localhost]: FAILED! => {"changed": true, "cmd": "grep \"nonexistent_pattern\" /etc/passwd", "delta": "0:00:00.002916", "end": "2023-07-14 16:10:23.671519", "msg": "non-zero return code", "rc": 1, "start": "2023-07-14 16:10:23.668603", "stderr": "", "stderr_lines": [], "stdout": "", "stdout_lines": []}
...ignoring
TASK [Display success or failure] *********************************************
ok: [localhost] => {
"msg": "Command failed with return code 1"
}
TASK [Run a custom failing command] *******************************************
fatal: [localhost]: FAILED! => {"changed": true, "cmd": "exit 3", "delta": "0:00:00.002447", "end": "2023-07-14 16:10:23.906121", "msg": "non-zero return code", "rc": 3, "start": "2023-07-14 16:10:23.903674", "stderr": "", "stderr_lines": [], "stdout": "", "stdout_lines": []}
...ignoring
TASK [Display detailed error information] *************************************
ok: [localhost] => {
"msg": "Return code: 3\nError message: No error message\n"
}
PLAY RECAP ********************************************************************
localhost : ok=3 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=2
This demonstrates how to capture and respond to different error conditions when running shell commands.
Creating a Practical Shell Output Processing Tool
In this final step, we'll bring together everything we've learned to create a practical Ansible playbook that collects system information, processes it, and generates a report. This represents a real-world scenario where Ansible's shell command processing capabilities can be extremely useful.
Building a System Information Report Tool
Let's create a comprehensive system information gathering tool:
- Create a new file called
system_report.ymlin the/home/labex/projectdirectory. - Add the following content:
---
- name: Comprehensive System Report
hosts: local
gather_facts: no
vars:
report_file: /tmp/system_report.txt
tasks:
- name: Collect basic system information
shell: |
echo "SYSTEM REPORT" > {{ report_file }}
echo "=============" >> {{ report_file }}
echo "" >> {{ report_file }}
echo "HOSTNAME: $(hostname)" >> {{ report_file }}
echo "TIMESTAMP: $(date)" >> {{ report_file }}
echo "" >> {{ report_file }}
echo "SYSTEM INFORMATION" >> {{ report_file }}
echo "------------------" >> {{ report_file }}
echo "OS: $(cat /etc/os-release | grep PRETTY_NAME | cut -d= -f2)" >> {{ report_file }}
echo "KERNEL: $(uname -r)" >> {{ report_file }}
echo "UPTIME: $(uptime -p)" >> {{ report_file }}
echo "" >> {{ report_file }}
echo "RESOURCE UTILIZATION" >> {{ report_file }}
echo "-------------------" >> {{ report_file }}
echo "CPU LOAD: $(uptime | awk -F'load average:' '{print $2}')" >> {{ report_file }}
echo "MEMORY USAGE:" >> {{ report_file }}
free -h >> {{ report_file }}
echo "" >> {{ report_file }}
echo "DISK USAGE:" >> {{ report_file }}
df -h >> {{ report_file }}
echo "" >> {{ report_file }}
echo "NETWORK INFORMATION" >> {{ report_file }}
echo "-------------------" >> {{ report_file }}
echo "IP ADDRESSES:" >> {{ report_file }}
ip addr | grep "inet " | awk '{print $2}' >> {{ report_file }}
echo "" >> {{ report_file }}
echo "PROCESS INFORMATION" >> {{ report_file }}
echo "-------------------" >> {{ report_file }}
echo "TOP 5 CPU CONSUMING PROCESSES:" >> {{ report_file }}
ps aux --sort=-%cpu | head -6 >> {{ report_file }}
echo "" >> {{ report_file }}
echo "TOP 5 MEMORY CONSUMING PROCESSES:" >> {{ report_file }}
ps aux --sort=-%mem | head -6 >> {{ report_file }}
register: report_generation
- name: Check if report was generated successfully
stat:
path: "{{ report_file }}"
register: report_stat
- name: Display report generation status
debug:
msg: "Report generated successfully at {{ report_file }}"
when: report_stat.stat.exists
- name: Display report content
shell: cat {{ report_file }}
register: report_content
when: report_stat.stat.exists
- name: Show report content
debug:
msg: "{{ report_content.stdout_lines }}"
when: report_stat.stat.exists
- name: Analyze disk usage
shell: df -h / | grep -v Filesystem | awk '{print $5}' | sed 's/%//'
register: disk_usage
when: report_stat.stat.exists
- name: Generate disk usage alert if needed
debug:
msg: "ALERT: Disk usage on / is {{ disk_usage.stdout }}% which exceeds the 80% threshold!"
when:
- report_stat.stat.exists
- disk_usage.stdout|int > 80
- name: Generate disk usage warning if needed
debug:
msg: "WARNING: Disk usage on / is {{ disk_usage.stdout }}% which exceeds the 60% threshold."
when:
- report_stat.stat.exists
- disk_usage.stdout|int > 60
- disk_usage.stdout|int <= 80
- name: Confirm normal disk usage
debug:
msg: "Disk usage on / is normal at {{ disk_usage.stdout }}%."
when:
- report_stat.stat.exists
- disk_usage.stdout|int <= 60
This playbook:
- Collects comprehensive system information using a series of shell commands
- Writes the information to a report file
- Verifies the report was created successfully
- Displays the content of the report
- Analyzes the disk usage data
- Generates appropriate alerts based on the analysis
Run the playbook:
ansible-playbook -i inventory.ini system_report.yml
You'll see comprehensive output showing the playbook execution and the full system report. The output is quite long, so here's just a sample of what you might see:
PLAY [Comprehensive System Report] ********************************************
TASK [Collect basic system information] ***************************************
changed: [localhost]
TASK [Check if report was generated successfully] *****************************
ok: [localhost]
TASK [Display report generation status] ***************************************
ok: [localhost] => {
"msg": "Report generated successfully at /tmp/system_report.txt"
}
TASK [Display report content] *************************************************
changed: [localhost]
TASK [Show report content] ****************************************************
ok: [localhost] => {
"msg": [
"SYSTEM REPORT",
"=============",
"",
"HOSTNAME: ubuntu-vm",
"TIMESTAMP: Fri Jul 14 16:35:42 UTC 2023",
"",
"SYSTEM INFORMATION",
"------------------",
"OS: \"Ubuntu 22.04.1 LTS\"",
"KERNEL: 5.15.0-1023-azure",
"UPTIME: up 3 hours, 25 minutes",
...
Examining the Report
Let's examine the system report we generated:
cat /tmp/system_report.txt
This will display the full report that was generated by our playbook.
Creating a Custom Shell Script and Calling It from Ansible
For more complex operations, it's sometimes easier to create a dedicated shell script and call it from Ansible:
- Create a new file called
disk_analyzer.shin the/home/labex/projectdirectory. - Add the following content:
#!/bin/bash
## disk_analyzer.sh - A simple script to analyze disk usage
echo "DISK USAGE ANALYSIS"
echo "------------------"
## Get overall disk usage
ROOT_USAGE=$(df -h / | grep -v Filesystem | awk '{print $5}' | sed 's/%//')
echo "Root filesystem usage: ${ROOT_USAGE}%"
## Categorize the usage
if [ $ROOT_USAGE -gt 80 ]; then
echo "STATUS: CRITICAL - Immediate action required"
elif [ $ROOT_USAGE -gt 60 ]; then
echo "STATUS: WARNING - Consider cleaning up disk space"
else
echo "STATUS: OK - Disk usage is within normal parameters"
fi
echo ""
## Find largest directories
echo "Top 5 largest directories in /var:"
du -h /var --max-depth=1 2> /dev/null | sort -hr | head -5
echo ""
## Find largest files
echo "Top 5 largest files in /var/log:"
find /var/log -type f -exec du -h {} \; 2> /dev/null | sort -hr | head -5
exit 0
- Make the script executable:
chmod +x /home/labex/project/disk_analyzer.sh
- Create a new playbook to call this script:
touch /home/labex/project/call_script.yml
- Add the following content to the playbook:
---
- name: Call Custom Shell Script
hosts: local
gather_facts: no
tasks:
- name: Run disk analyzer script
shell: /home/labex/project/disk_analyzer.sh
register: script_output
- name: Display script output
debug:
msg: "{{ script_output.stdout_lines }}"
- name: Check for critical status
debug:
msg: "CRITICAL DISK USAGE DETECTED! Immediate action required."
when: script_output.stdout is search("STATUS: CRITICAL")
- Run the playbook:
ansible-playbook -i inventory.ini call_script.yml
You should see output similar to this:
PLAY [Call Custom Shell Script] ***********************************************
TASK [Run disk analyzer script] ***********************************************
changed: [localhost]
TASK [Display script output] **************************************************
ok: [localhost] => {
"msg": [
"DISK USAGE ANALYSIS",
"------------------",
"Root filesystem usage: 38%",
"STATUS: OK - Disk usage is within normal parameters",
"",
"Top 5 largest directories in /var:",
"60M\t/var/lib",
"60M\t/var/cache",
"12M\t/var/log",
"4.0K\t/var/tmp",
"4.0K\t/var/mail",
"",
"Top 5 largest files in /var/log:",
"4.0M\t/var/log/journal/c75af53674ce472fb9654a1d5cf8cc37/system.journal",
"2.3M\t/var/log/auth.log",
"1.3M\t/var/log/syslog",
"724K\t/var/log/kern.log",
"428K\t/var/log/cloud-init.log"
]
}
TASK [Check for critical status] **********************************************
skipped: [localhost]
PLAY RECAP ********************************************************************
localhost : ok=2 changed=1 unreachable=0 failed=0 skipped=1 rescued=0 ignored=0
This approach combines the power of shell scripts with Ansible's automation capabilities. The shell script handles the complex logic for disk analysis, while Ansible manages the execution and further processing of the results.
Key Takeaways
Through this lab, you've learned several important techniques for working with shell command output in Ansible:
- How to execute shell commands and capture their output
- How to process and format command output for display
- How to use conditional execution based on command results
- How to handle JSON output and error conditions
- How to create practical tools that combine shell commands with Ansible's automation capabilities
These skills will be invaluable as you build more complex automation solutions with Ansible.
Summary
In this lab, you learned how to effectively work with shell command output in Ansible playbooks. Starting with the basics of executing shell commands and capturing their output, you progressed to more advanced techniques like conditional execution, error handling, and processing structured data formats like JSON.
You've mastered several key skills:
- Running shell commands in Ansible playbooks using the
shellmodule - Capturing command output with the
registerdirective - Displaying output using the
debugmodule - Processing output with Jinja2 filters and conditionals
- Creating practical automation tools that combine Ansible with shell scripts
These techniques enable you to create more dynamic and responsive automation workflows that can adapt to different system conditions and provide useful feedback about the operations being performed.
As you continue your Ansible journey, remember that while shell commands provide great flexibility, Ansible's built-in modules are often a more robust and portable solution for common tasks. Use shell commands when you need to leverage existing shell scripts or perform complex operations that aren't easily handled by Ansible modules.


