3
\$\begingroup\$

This is a simple Bash script to provide menu driven manuals and standard operating procedures.

Sops and mans with the extension .sopman.txt will be loaded.

The file motd is required, it is intended to prompt the user with a banner containing useful and or up to date information.

Use the markup +color+ to colorize a line, see colors.sopman.txt for complete list of supported colors.

Github Project

See Find and Replace Question

Powershell Version Code Review

#!/usr/bin/env bash
#.-----.-----.-----.--------.---.-.-----.
#|__ --|  _  |  _  |        |  _  |     |
#|_____|_____|   __|__|__|__|___._|__|__|
#            |__|   Matthew A. Brassey
version=1.0.0

license="
sopman v${version}
Copyright (C) 2017  Matthew A. Brassey

        This program is free software: you can redistribute it and/or modify
        it under the terms of the GNU General Public License as published by
        the Free Software Foundation, either version 3 of the License, or
        (at your option) any later version.

        This program is distributed in the hope that it will be useful,
        but WITHOUT ANY WARRANTY; without even the implied warranty of
        MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
        GNU General Public License for more details.

        You should have received a copy of the GNU General Public License
        along with this program.  If not, see <http://www.gnu.org/licenses/>.
"

help="
Usage: ./sopman.sh [--help|--version]

[options]
        --search        Search sopman archive for a string. '--search <search string>'
        --motd          Display message of the day.
        --license       Show lisense information.
"

#Variables
args=("$@")
sops=(sops/*.sopman.txt)
stoploop="false"
endscript="false"
length="${#sops[@]}"

#Colors
lineColor='\e[0m'
reset="\e[0m";
black="\e[1;30m";
blue="\e[1;34m";
cyan="\e[1;36m";
green="\e[1;32m";
purple="\e[1;35m";
red="\e[1;31m";
white="\e[1;37m";
yellow="\e[1;33m";
header="$(echo -e "${cyan}================================================================[sopman]====${reset}")"
footer="$(echo -e "${cyan}============================================================================${reset}")"

#Functions
function search() {
    echo -e "${green}Search results for \"$searchString\":${reset}\n"
    grep -rnw sops/ -e "$searchString" --include "*.sopman.txt"
}

function motd() {
       clear
       echo "$header"
       while read -r line; do
           GETCOLOR "$line"
           newLine=$(echo "$line" | sed "s/+[a-Z]\++//g")
#           shopt -s extglob
#           new_line=${line//(\+)}
           echo -e "${lineColor}${newLine}${reset}"
       done <"motd"
       echo "$footer"
}

function menu0 {
    fcount="0"
    clear
    echo "$header"
    motd
    echo -e "${green}0] Search ${reset}"
    for sop in "${sops[@]}"
    do
        let fcount=fcount+1
        echo -e "${green}$fcount) ${sop:5:-11} ${reset}"
    done
    echo "$footer"
}

function GETCOLOR() {
        if [[ $1 =~ \+[a-Z]+\+? ]]; then
          local match=${BASH_REMATCH[0]};
          case $match in
            "+black+") lineColor=$black;;
            "+red+") lineColor=$red;;
            "+green+") lineColor=$green;;
            "+blue+") lineColor=$blue;;
            "+purple+") lineColor=$purple;;
            "+cyan+") lineColor=$cyan;;
            "+yellow+") lineColor=$yellow;;
            "+white+") lineColor=$white;;
            *) lineColor=$reset;;
          esac
        fi
}

for ((arg=0;arg<"${#args[@]}";arg++)); do
        [ "${args[$arg]}" == "--version" ] && echo "${version}" && exit
        [ "${args[$arg]}" == "--help" ] && echo "${help}" && exit
        [ "${args[$arg]}" == "--license" ] && echo "${license}" && exit
        [ "${args[$arg]}" == "--search" ] && searchString=${args[$arg+1]} && clear && echo "$header" && search && echo "$footer" && exit
        [ "${args[$arg]}" == "--motd" ] && clear && echo "$header" && motd && exit
        #[ "${args[$arg]}" == "--" ] && echo ${args[$arg]}
done

while [ $endscript = "false" ]
do
        menu0 
        while [ $stoploop = "false" ]
        do
                printf "Enter your selection (q to quit) : "
                read -r input1
                if [ "$input1" = "q" ]; then
                echo -e "${cyan}Bye-Bye${reset}"
                exit
                fi
                if [ "$input1" -eq "0" ]; then
                printf "Search for: "
                read -r searchString
                clear
                echo "$header"
                search
                echo "$footer"
                printf "[ 'm' to return to menu, anything else to quit ] : "
                read -r input3
                if [ "$input3" = "m" ]; then
                        break
                else 
                        echo -e "${cyan}Bye-Bye${reset}"
                        exit
                fi
                fi
                if [ "$input1" -ge "1" ] && [ "$input1" -le "$length" ]; then
                        clear
                        echo "$header"
                          while read -r line; do
                            GETCOLOR "$line"
                            newLine=$(echo "$line" | sed "s/+[a-Z]\++//g")
                            echo -e "${lineColor}${newLine}${reset}"
                          done <"${sops[$input1-1]}"
                        echo "$footer"
                        printf "[ 'm' to return to menu, anything else to quit ] : "
                        read -r input2
                        if [ "$input2" = "m" ]; then
                                break
                        else
                                echo -e "${cyan}Bye-Bye${reset}"
                                exit
                        fi
                else
                        echo -e "${red}ERROR! Please select an option : ${reset}"
                        retryCount=$((retryCount+1))
                        if [ "$retryCount" -ge "3" ]; then
                        echo -e "${red}EXIT!${reset}"
                        exit
                        fi
                fi
        done
done
\$\endgroup\$
  • \$\begingroup\$ What are you looking for from the code review? \$\endgroup\$ – chicks Mar 18 '17 at 22:32
  • \$\begingroup\$ It would be great to have an answer to the Find and Replace Question. Also looking for corrections, optimizations & general improvements or suggestions. \$\endgroup\$ – Matt Mar 19 '17 at 0:09
2
\$\begingroup\$

I don't have time for a full review, but I'll just mention that you seem to have terminal-specific escapes here:

lineColor='\e[0m'
reset="\e[0m";
black="\e[1;30m";
blue="\e[1;34m";
cyan="\e[1;36m";
green="\e[1;32m";
purple="\e[1;35m";
red="\e[1;31m";
white="\e[1;37m";
yellow="\e[1;33m";

Assuming these are supposed to be Linux console escapes, they can be more portably written thus:

reset="$(tput sgr0)"
lineColor="$reset"
black="$(tput bold; tput setaf 0)"
blue="$(tput bold; tput setaf 4)"
cyan="$(tput bold; tput setaf 6)"
green="$(tput bold; tput setaf 2)"
purple="$(tput bold; tput setaf 5)"
red="$(tput bold; tput setaf 1)"
white="$(tput bold; tput setaf 7)"
yellow="$(tput bold; tput setaf 3)"

The above produces real terminal escapes, so you'll be able to drop the non-POSIX -e flag to echo. That's a Good Thing, but you will need to properly quote their expansions.


In GETCOLOR, where these codes are interpolated, there's a very repetitive switch statement:

      case $match in
        "+black+") lineColor=$black;;
        "+red+") lineColor=$red;;
        #....
      esac

It looks like it would be easier to just substitute the variable name, using ${! }:

function GETCOLOR() {
    if [[ $1 =~ \+[a-Z]+\+? ]]
    then
        local match="${BASH_REMATCH[0]}"
        case "$match" in
            +black+|+red+|+green+|+blue+|+purple+|+cyan+|+yellow+|+white+)
                match="${match//+}"
                lineColor="${!match}"
                ;;
            *)
                lineColor="$reset"
                ;;
        esac
    fi
}

That can be simplified further, by using a capture group for the word inside +...+:

function GETCOLOR() {
    if [[ $1 =~ \+([a-Z]+)\+? ]]
    then
        local match="${BASH_REMATCH[1]}"
        case "$match" in
            black|red|green|blue|purple|cyan|yellow|white)
                lineColor="${!match}"
                ;;
            *)
                lineColor="$reset"
                ;;
        esac
    fi
}
\$\endgroup\$
  • \$\begingroup\$ Excellent response. I updated the Github Project per your suggestions. \$\endgroup\$ – Matt Mar 22 '17 at 5:24
  • \$\begingroup\$ I followed your link - there's a few more places where echo -e is still used, but the -e is no longer needed. And "($echo -e something)" can simplify to "something" for header and footer. \$\endgroup\$ – Toby Speight Mar 22 '17 at 8:47

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.