Ops Scripting w. BASH: Frequency
Tracking Frequency in BASH (Bourne Again Shell): Part I
Operations oriented roles, almost always require skills in automation and scripting with shell programming. These days with the ubiquity of Linux and GNU command line tools, GNU Bash has become ubiquitous.
Bash combined with command line tools, is regulated for small automation chores, data structures are supports strings, integers, and arrays. However, starting with Bash 4, you can use more advanced data structures like associative arrays (hashes, maps, or dictionaries) to create data structures that are used for algorithms like tracking frequency.
This problem and later solutions, show how to use a Bash associative array to track frequency, and along the way, show some cool tricks that you can use with Bash.
But first you need to make sure Bash 4 or higher is available on your system…
Getting Bash 4+
If you have a recent Linux distro, such as Debian, Ubuntu, CentOS, a current version of Bash 5 is already installed.
macOS
Apple’s macOS (aka Mac OS X) comes a very old 15-year old version of Bash. With Homebrew package manager, you can get a recent version of Bash:
brew install bash
sudo bash -c 'echo /usr/local/bin/bash >> /etc/shells'
chsh -s /usr/local/bin/bash
Windows
On Windows 10, we can use MSYS2 (Minimal System 2) that comes with a recent version of Bash. You can install MSYS2 with the package manager Chocolatey from either a command shell (cmd.exe
) or PowerShell (powershell.exe
) in Administrative mode:
choco install msys2
The Problem
The goal of this exercise is to print a summary of shell usage on a system. For this exercise, we’ll do it in two parts:
- Build a data structure containing the shell counts, called
COUNTS
from a supplied local password file./passwd
. - Given the shell counts data structure
COUNTS
, produce a report.
The Data
Here’s the passwd
file you will use for this exercise:
The Output
When generating a report, the output should look like this:
Shell Summary Report:
==================================================
Shell # of Users
----------------- ------------
/bin/bash 3 users
/bin/false 7 users
/bin/sync 1 users
/usr/sbin/nologin 17 users
The Code
Here is sample code to get you started:
Code Notes
These are some of the techniques used in the code above.
Formatted Output
We printf
command (see printf), which behaves like the C-Language counterpart:
printf FORMATTED_STRING STRING1 STRING2 STRING3
printf "%s %s %s\n" STRING1 STRING2 STRING3
Repetition
You can use repetition to print out, a line for example, using this technique:
printf '=%.0s' {1..10}
This will generate ten equal symbols. This itself can be wrapped into a sub-shell $()
or ``
it is needs to be concatenated with another string.
Enumerating Keys
The keys and values of an associative array in Bash can be enumerated with this notation:
KEYS = "${!ASSOC_ARRAY[@]}"
VALUES = "${ASSOC_ARRAY[@]}"
If you put these into a subshell, you then sort the keys.
SORTED_KEYS = $(echo ${![ASSOC_ARRAY[@]} | sort)
Referencing a Value
You can extract a value given a key like this:
VALUE = ${ASSOC_ARRAY[$KEY]}
Next Article
Ops Scripting w. Bash: Frequency 2
Tracking Frequency in BASH (Bourne Again Shell): Part II
medium.com
The Conclusion
For now, I’ll just present the problem, and next article I will present some solutions.
With the sample code, you can get the following takeaways for Bash
- Creating an Associative Array with
declare -A
- Enumerating Keys and Values from an associative array
- Referencing (looking up) an item from the associative array
- Formatted output with
printf
- Repetition using
printf "%.0s=" {1..10}
trick