Skip to content

Instantly share code, notes, and snippets.

@janderudder
Last active January 11, 2021 14:50

Revisions

  1. janderudder renamed this gist Jan 11, 2021. 1 changed file with 27 additions and 14 deletions.
    41 changes: 27 additions & 14 deletions mg.sh → mangrep.sh
    Original file line number Diff line number Diff line change
    @@ -1,6 +1,5 @@
    #!/bin/bash


    declare -r Base_name=$(basename -s .sh "$0")


    @@ -13,7 +12,7 @@ Conveniently lookup a keyword in a man page.
    Usage:
    ${Base_name} [GREP-OPTIONS... [--]] COMMAND KEYWORD
    GREP-OPTIONS (optional)
    GREP-OPTIONS (facultative)
    Options that will be passed directly to grep.
    You may end this list with '--' to avoid ambiguity.
    @@ -22,7 +21,7 @@ COMMAND
    KEYWORD
    The sequence of characters to search for in the man page of COMMAND.
    This could be a Grep's pattern, but will typically be just a flag.
    This can be a grep pattern, but will typically be just an option flag.
    Examples:
    ${Base_name} ls -A
    @@ -88,6 +87,20 @@ say_more_info()
    }


    #
    # Error codes
    #
    declare -ri Error_not_enough_parameters=1
    declare -ri Error_invalid_grep_color_opt=2
    declare -ri Error_command_param_is_opt=3
    declare -ri Error_too_many_keywords=4
    declare -ri Error_missing_grep_flags_end=5
    declare -ri Error_missing_command_param=6
    declare -ri Error_missing_keyword_param=7
    declare -ri Error_command_not_found=8
    declare -ri Error_grep_not_found=9


    #
    # Entry point
    #
    @@ -104,7 +117,7 @@ main()
    then
    \echo "Need at least two parameters."
    say_more_info
    exit 1
    exit $Error_not_enough_parameters
    fi

    #
    @@ -133,7 +146,7 @@ main()
    else
    \echo "${Base_name} error: invalid color option for grep ("$1")."
    say_more_info
    \exit 2
    \exit $Error_invalid_grep_color_opt
    fi
    else
    Grep_flags+=("$1")
    @@ -146,7 +159,7 @@ main()
    then
    \echo "${Base_name}: error in command name ("$1"). Abort"
    say_more_info
    \exit 3
    \exit $Error_command_param_is_opt
    fi
    Command="$1"
    }
    @@ -191,9 +204,9 @@ main()

    elif [[ $Parsing_phase -eq ${Phase[DONE]} ]];
    then
    \echo "Too much search keywords."
    \echo "Too many search keywords."
    say_more_info
    exit 4
    \exit $Error_too_many_keywords
    fi

    done
    @@ -220,18 +233,18 @@ main()
    \echo "${Base_name} error: grep flags string not terminated"\
    "(missing '--')."
    say_more_info
    exit 5
    \exit $Error_missing_grep_flags_end
    fi

    elif [[ $Parsing_phase -eq ${Phase[COMMAND]} ]]; then
    \echo "${Base_name} error: missing command name."
    say_more_info
    exit 6
    \exit $Error_missing_command_param

    elif [[ ${#Search_flag} -eq 0 ]]; then
    \echo "${Base_name} error: missing flag to search for."
    \echo "${Base_name} error: missing keyword (flag to search for)."
    say_more_info
    exit 7
    \exit $Error_missing_keyword_param

    fi

    @@ -241,7 +254,7 @@ main()
    if ! command_exists "$Command"
    then
    \echo "${Base_name} error: couldn't find or execute \"$Command\"."
    exit 8
    \exit $Error_command_not_found
    fi

    #
    @@ -255,7 +268,7 @@ main()

    if [[ ! -x $Grep ]]; then
    \echo "${Base_name} error: couldn't find grep. Abort."
    exit 9
    \exit $Error_grep_not_found
    fi
    fi

  2. janderudder revised this gist Oct 4, 2020. No changes.
  3. janderudder created this gist Oct 4, 2020.
    272 changes: 272 additions & 0 deletions mg.sh
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,272 @@
    #!/bin/bash


    declare -r Base_name=$(basename -s .sh "$0")


    help()
    {
    cat <<-EOD
    Man Grep
    Conveniently lookup a keyword in a man page.
    Usage:
    ${Base_name} [GREP-OPTIONS... [--]] COMMAND KEYWORD
    GREP-OPTIONS (optional)
    Options that will be passed directly to grep.
    You may end this list with '--' to avoid ambiguity.
    COMMAND
    The name of the command of which the man page will be scanned.
    KEYWORD
    The sequence of characters to search for in the man page of COMMAND.
    This could be a Grep's pattern, but will typically be just a flag.
    Examples:
    ${Base_name} ls -A
    ${Base_name} -w ls -a
    ${Base_name} --color=auto -- man --warnings
    EOD
    }


    #
    # Utilities
    #
    init_enum_array()
    {
    declare -n Arr=$1
    shift
    declare -i i=0
    for Elem in $@;
    do
    Arr+=([$Elem]=$((i++)))
    done
    }


    command_exists()
    {
    \type "$1" &> /dev/null
    \return $?
    }


    is_opt()
    {
    [[ $1 =~ ^-.*$ ]]
    \return $?
    }


    is_opt_help()
    {
    case "$1" in '--help'|'-help'|'-h'|'-?')
    \return $(true)
    esac
    \return $(false)
    }


    validate_color_option()
    {
    Tail=${1:${#1}-4:4}

    case $Tail in 'auto'|'ever'|'ways')
    return $(true)
    esac
    \return $(false)
    }


    say_more_info()
    {
    \echo "Type '${Base_name} --help' for usage information."
    }


    #
    # Entry point
    #
    main()
    {
    #
    # Command line validation, rough first pass
    #
    if is_opt_help "$1"; then
    help;
    exit 0

    elif [[ $# -lt 2 ]];
    then
    \echo "Need at least two parameters."
    say_more_info
    exit 1
    fi

    #
    # Variables for arguments parsing
    #
    declare -a Grep_flags=()
    \declare Search_flag=""
    \declare Command=""
    \declare Color_flag='--color=auto'
    \declare -i Parsing_phase
    \declare -A Phase
    init_enum_array Phase 'START GREP_OPT COMMAND KEYWORD DONE'

    #
    # Nested functions for argument parsing
    #
    parse_grep_option()
    {
    if [[ $1 = '--' ]]; then
    Parsing_phase=${Phase[COMMAND]}

    elif [[ $1 =~ ^--colou?r=.*$ ]];
    then
    if validate_color_option "$1"; then
    Color_flag="$1"
    else
    \echo "${Base_name} error: invalid color option for grep ("$1")."
    say_more_info
    \exit 2
    fi
    else
    Grep_flags+=("$1")
    fi
    }

    parse_command_name()
    {
    if is_opt "$1"
    then
    \echo "${Base_name}: error in command name ("$1"). Abort"
    say_more_info
    \exit 3
    fi
    Command="$1"
    }

    #
    # Do argument parsing
    #
    for Arg in $@;
    do
    if [[ $Parsing_phase -eq ${Phase[START]} ]];
    then
    if is_opt_help "$Arg"
    then
    help;
    exit 0

    elif [[ $Arg = '--' ]]; then
    Parsing_phase=${Phase[COMMAND]}

    elif is_opt "$Arg"; then
    Parsing_phase=${Phase[GREP_OPT]}
    parse_grep_option "$Arg"

    else
    parse_command_name "$Arg"
    Parsing_phase=${Phase[KEYWORD]}
    fi

    elif [[ $Parsing_phase -eq ${Phase[GREP_OPT]} ]];
    then
    parse_grep_option "$Arg"

    elif [[ $Parsing_phase -eq ${Phase[COMMAND]} ]];
    then
    parse_command_name "$Arg"
    Parsing_phase=${Phase[KEYWORD]}

    elif [[ $Parsing_phase -eq ${Phase[KEYWORD]} ]];
    then
    Search_flag="$Arg"
    Parsing_phase=${Phase[DONE]}

    elif [[ $Parsing_phase -eq ${Phase[DONE]} ]];
    then
    \echo "Too much search keywords."
    say_more_info
    exit 4
    fi

    done

    #
    # Check and validate parsing
    #
    if [[ $Parsing_phase -eq ${Phase[GREP_OPT]} ]];
    # Here we try to repair the situation where the user forgot to pass '--'
    # after grep options to change parsing phase.
    # So we check if flag[last-2] is not starting with '-', and try to use
    # last two flags as command name and search pattern.
    then
    GF_count=${#Grep_flags[@]}

    if [[ $GF_count -gt 1 ]] && ! is_opt "${Grep_flags[$((GF_count-2))]}"
    then
    Search_flag="${Grep_flags[$((GF_count-1))]}"
    Command="${Grep_flags[$((GF_count-2))]}"
    unset Grep_flags[-2]
    unset Grep_flags[-1]

    else
    \echo "${Base_name} error: grep flags string not terminated"\
    "(missing '--')."
    say_more_info
    exit 5
    fi

    elif [[ $Parsing_phase -eq ${Phase[COMMAND]} ]]; then
    \echo "${Base_name} error: missing command name."
    say_more_info
    exit 6

    elif [[ ${#Search_flag} -eq 0 ]]; then
    \echo "${Base_name} error: missing flag to search for."
    say_more_info
    exit 7

    fi

    #
    # Check command validity
    #
    if ! command_exists "$Command"
    then
    \echo "${Base_name} error: couldn't find or execute \"$Command\"."
    exit 8
    fi

    #
    # Configure grep
    #
    declare Grep='/usr/bin/grep'

    if [[ ! -x $Grep ]];
    then
    Grep='/bin/grep'

    if [[ ! -x $Grep ]]; then
    \echo "${Base_name} error: couldn't find grep. Abort."
    exit 9
    fi
    fi

    #
    # Exec search in command's help
    #
    $Grep "${Grep_flags[@]}" "$Color_flag" -- "${Search_flag}" <(man ${Command})

    }

    #
    # Launch
    #
    main $@