Skip to content

Instantly share code, notes, and snippets.

@kou1okada
Last active January 11, 2022 11:52
Show Gist options
  • Save kou1okada/fee040cb15321ea438a3d51c2b05044e to your computer and use it in GitHub Desktop.
Save kou1okada/fee040cb15321ea438a3d51c2b05044e to your computer and use it in GitHub Desktop.
hgrep - grep wrapper for saving header

hgrep

This script is the grep wrapper for saving header.

Usage

hgrep [OPTIONS ...] [FILES ...]
Options:
  See help or manpage of grep commnand.

Copyright

Copyright (c) 2019 Koichi OKADA. All rights reserved.

License

This script is distributed under the MIT license.

Relations

#!/usr/bin/env bash
# grep wrapper for saving header.
# Copyright (c) 2019 Koichi OKADA. All rights reserved.
# This script is distributed under the MIT license.
(( 5 <= DEBUG )) && set -x
function function_get_lines () # PAT_FUNC [FILE]
# Return lines of function about declare, begin and end.
{
grep -nE "^$1|^{|^}" "${@:2:1}" \
| grep -A2 -E "^[0-9]+:$1" \
| grep -o -E "^[0-9]+"
}
function headtail () # FIRST_LINE LAST_LINE
# Split lines from FIRST_LINE to LAST_LINE.
{
head -n+$2 | tail -n+$1
}
function uniqex ()
# An alternative uniq command which is not required sort
{
awk '!c[$0]++'
}
function show_options ()
{
local i
echo "Options:"
echo " OPT0:" ; for i in "${OPT0[@]}" ; do echo " $i"; done
echo " OPT1:" ; for i in "${OPT1[@]}" ; do echo " $i"; done
echo " OPT01:"; for i in "${OPT01[@]}"; do echo " $i"; done
}
function usage_default () #= [CMD [DISPLAY_NAME]]
# Auto generate default usage from documentation
# Args:
# CMD : Whole name of subcommand
{
local CMD="${1:-$CMD}"
local DISPLAY_NAME="${2:-$CMD}"
local PAT_FUNC_CMD="function +${CMD} *\( *\)"
local lines src srcs
readarray -t srcs < <(grep -lE "$PAT_FUNC_CMD" "${BASH_SOURCE[@]}" | tac | uniqex)
[ -z "$srcs" ] && { echo "Error: function ${CMD} is not founded."; exit 1; }
src="$srcs"
readarray -t lines < <(function_get_lines "$PAT_FUNC_CMD" "$src")
cat "$src" \
| headtail $(( lines[0] )) $(( lines[1] - 1 )) \
| sed -r -e 's/^(function +)('"$CMD"')( *\( *\))/\1'"$DISPLAY_NAME"'\3/g' \
| sed -r -e 's/^function +([^ ]+)[^#]*(#=? *(.*))?/Usage: \1 \3/g' \
-e 's/^#\?? (.*)/\1/g'
show_options
}
function optparse () # [OPTIONS ...] [ARGUMENTS ...]
# Parse options of COMMAND, and update conditions for wrapping it.
# Before call this function, COMMAND must be gotten options with `get_options`.
# Returns:
# ARGS[@] : positional parameters
# OPTS[@] : options of COMMAND
{
local short param KEYDEF
shopt -q extglob; local extglob=$?; shopt -s extglob
ARGS=()
while (( 0 < $# )); do
short=
param=
if [[ "${1:0:2}" = "--" && "$1" != "${1/=/}" ]];then
param=1
set -- "${1%%=*}" "${1#*=}" "${@:2}"
elif [[ "${1:0:2}" != "--" && "${1:0:1}" = "-" && 2 < "${#1}" ]]; then
short=1
param=1
set -- "${1:0:2}" "${1:2}" "${@:2}"
fi
case "$1" in
-h|--help)
OPT_HELP="$1"
;;&
--debug)
OPT_DEBUG="$1"
;;&
$OPT01) # [PARAM]
if [[ "$param" = 1 ]]; then
OPTS+=( "$1=$2" )
shift 2
else
OPTS+=( "$1" )
shift 1
fi
;;
$OPT1) # PARAM
OPTS+=( "$1" "$2" )
shift 2
;;
$OPT0) #
OPTS+=( "$1" )
[[ -z "$short" && -n "$param" ]] && {
echo "Warning: taking a unexpected parameter for $1: $2"
set -- "${@:1:1}" "${@:3}"
}
[[ -n "$short" && -n "$param" ]] && set -- "${@:1:1}" "-${@:2:1}" "${@:3}"
shift 1
;;
--)
ARGS=( "${@:2}" )
shift $#
;;
-*)
echo "Error: unknown option: $1"
exit 1
;;
*)
ARGS+=( "$1" )
shift 1
;;
esac
done
[ "$extglob" = "1" ] && shopt -u extglob
}
function get_options () # <COMMAND>
# Get options of COMMAND.
# Returns:
# OPT0 : Options for case statement which take no parameters.
# OPT1 : Options for case statement which take a parameter.
# OPT01 : Options for case statement which take a optional parameter.
{
local tmp opt opts
OPT0=""
OPT1=""
OPT01=""
readarray -t opts < <("$1" --help|grep -E "^ *-"|sed -r -e 's/^ *//g' -e 's/^((-[^-])?((, +)?--[^ ,]+)*).*/\1/g')
for opt in "${opts[@]}"; do
tmp="${opt//\[=*/}"
tmp="${tmp//=*/}"
tmp="${tmp// /}"
tmp="${tmp//,/|}"
if [[ "$opt" = "${opt/=/}" ]]; then
OPT0+="${OPT0:+|}$tmp"
elif [[ "${opt}" =~ \[= ]]; then
OPT01+="${OPT01:+|}$tmp"
else
OPT1+="${OPT1:+|}$tmp"
fi
done
OPT0="@($OPT0)"
OPT1="@($OPT1)"
OPT01="@($OPT01)"
}
function main () # [OPTIONS ...] [FILES ...]
# grep wrapper for saving header.
# Options:
# See help or manpage of grep command as:
# grep --help
# man grep
{
local OPT0 OPT1 OPT01
local ARGS OPTS
local TEMPLATES="" FIELDS="" KEYCOUNT=1
local filter
local header
get_options grep
optparse "$@"
if [ -n "$OPT_HELP" ]; then
usage_default "$FUNCNAME" "${0##*/}"
return
fi
if [ -n "$OPT_DEBUG" ]; then
filter=( "cat" )
else
filter=( sed -r -e 's/^([^,]*,){'"$KEYCOUNT"'}//g' )
fi
{
read header; printf "%s\n" "$header"
grep "${OPTS[@]}" "${ARGS[@]}"
} | "${filter[@]}"
}
main "$@"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment