File: hawk.sh 1 #!/bin/sh 2 3 # The MIT License (MIT) 4 # 5 # Copyright (c) 2026 pacman64 6 # 7 # Permission is hereby granted, free of charge, to any person obtaining a copy 8 # of this software and associated documentation files (the "Software"), to deal 9 # in the Software without restriction, including without limitation the rights 10 # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 # copies of the Software, and to permit persons to whom the Software is 12 # furnished to do so, subject to the following conditions: 13 # 14 # The above copyright notice and this permission notice shall be included in 15 # all copies or substantial portions of the Software. 16 # 17 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 # SOFTWARE. 24 25 26 # hawk [options...] [awk condition] [filenames...] 27 # 28 # 29 # Highlight (lines) satisfying an AWK condition/expression, keeping other 30 # lines the same. When not given a condition, all lines are highlighted. 31 # 32 # The handy case-insensitive shortcut options may cause this tool to fail, 33 # if the main AWK tool installed doesn't support the special IGNORECASE 34 # variable. 35 # 36 # The AWK options available only in single-dash versions are 37 # 38 # -F fs use `fs` for the field separator (the `FS` variable) 39 # -V show the AWK version installed 40 # -v var=val set a variable to a given value 41 # 42 # The other options are, available both in single and double-dash versions 43 # 44 # -h, -help show this help message 45 # -ins, -insensitive match regexes case-insensitively; fail if unsupported 46 # -tsv split fields using tabs, same as using -F "\t" 47 # 48 # -blue use a blue style 49 # -gray use a gray style 50 # -green use a green style 51 # -orange use an orange style 52 # -purple use a purple style 53 # -red use a red style 54 # 55 # -bb, -blueback use a blue-background style 56 # -grayback use a gray-background style 57 # -gb, -greenback use a green-background style 58 # -ob, -orangeback use an orange-background style 59 # -pb, -purpleback use a purple-background style 60 # -rb, -redback use a red-background style 61 62 63 case "$1" in 64 -h|--h|-help|--help) 65 awk '/^# +hawk /, /^$/ { gsub(/^# ?/, ""); print }' "$0" 66 exit 0 67 ;; 68 esac 69 70 ansi='7m' 71 command='awk' 72 if { [ -p /dev/stdout ] || [ -t 1 ]; } && [ -e /usr/bin/stdbuf ]; then 73 command='stdbuf -oL awk' 74 fi 75 76 case_insensitive=0 77 78 while [ $# -gt 0 ]; do 79 arg="$1" 80 81 if [ "${arg}" = "--" ]; then 82 shift 83 break 84 fi 85 86 case "${arg}" in 87 -F) 88 shift 89 if [ $# -eq 0 ]; then 90 printf "expected value after -F option\n" >&2 91 exit 1 92 fi 93 command="${command} -F $1" 94 shift 95 continue 96 ;; 97 98 -F*) 99 command="${command} ${arg}" 100 shift 101 continue 102 ;; 103 104 -v) 105 shift 106 if [ $# -eq 0 ]; then 107 printf "expected variable assignment after -v option\n" >&2 108 exit 1 109 fi 110 command="${command} -v $1" 111 shift 112 continue 113 ;; 114 115 -ins|--ins|-insensitive|--insensitive) 116 case_insensitive=1 117 shift 118 continue 119 ;; 120 121 -tsv|--tsv) 122 command="${command} -F \"\\t\"" 123 shift 124 continue 125 ;; 126 127 -blue|--blue) 128 ansi='38;2;0;95;215m' 129 shift 130 continue 131 ;; 132 133 -bb|--bb|-blueback|--blueback) 134 ansi='48;2;0;95;215m\x1b[38;2;238;238;238m' 135 shift 136 continue 137 ;; 138 139 -bold|--bold|-bolded|--bolded) 140 ansi='1m' 141 shift 142 continue 143 ;; 144 145 -dim|--dim|-faint|--faint|-gray|--gray) 146 ansi='38;2;168;168;168m' 147 shift 148 continue 149 ;; 150 151 -grayback|--grayback) 152 ansi='48;2;168;168;168m\x1b[38;2;238;238;238m' 153 shift 154 continue 155 ;; 156 157 -green|--green) 158 ansi='38;2;0;135;95m' 159 shift 160 continue 161 ;; 162 163 -gb|--gb|-greenback|--greenback) 164 ansi='48;2;0;135;95m\x1b[38;2;238;238;238m' 165 shift 166 continue 167 ;; 168 169 -inv|--inv|-inverse|--inverse|-invert|--invert|-inverted|--inverted) 170 ansi='7m' 171 shift 172 continue 173 ;; 174 175 -orange|--orange) 176 ansi='38;2;215;95;0m' 177 shift 178 continue 179 ;; 180 181 -ob|--ob|-orangeback|--orangeback) 182 ansi='48;2;215;95;0m\x1b[38;2;238;238;238m' 183 shift 184 continue 185 ;; 186 187 -purple|--purple) 188 ansi='38;2;135;95;255m' 189 shift 190 continue 191 ;; 192 193 -pb|--pb|-purpleback|--purpleback) 194 ansi='48;2;135;95;255m\x1b[38;2;238;238;238m' 195 shift 196 continue 197 ;; 198 199 -red|--red) 200 ansi='38;2;204;0;0m' 201 shift 202 continue 203 ;; 204 205 -rb|--rb|-redback|--redback) 206 ansi='48;2;204;0;0m\x1b[38;2;238;238;238m' 207 shift 208 continue 209 ;; 210 211 -strike|--strike|-striked|--striked|-stricken|--stricken) 212 ansi='9m' 213 shift 214 continue 215 ;; 216 217 -underline|--underline|-underlined|--underlined) 218 ansi='4m' 219 shift 220 continue 221 ;; 222 223 -*) 224 command="${command} ${arg}" 225 shift 226 continue 227 ;; 228 esac 229 230 break 231 done 232 233 cond="${1:-1}" 234 [ $# -gt 0 ] && shift 235 236 # show all non-existing files given 237 failed=0 238 for arg in "$@"; do 239 if [ "${arg}" = "-" ]; then 240 continue 241 fi 242 if [ ! -e "${arg}" ]; then 243 printf "no file named \"%s\"\n" "${arg}" > /dev/stderr 244 failed=1 245 fi 246 done 247 248 if [ "${failed}" -gt 0 ]; then 249 exit 2 250 fi 251 252 ci=' 253 BEGIN { 254 if (IGNORECASE == "") { 255 m = "your `awk` command lacks case-insensitive regex-matching" 256 printf("\x1b[38;2;204;0;0m%s\x1b[0m\n", m) > "/dev/stderr" 257 exit 125 258 } 259 IGNORECASE = 1 260 } 261 ' 262 if [ "${case_insensitive}" -eq 0 ]; then 263 ci='' 264 fi 265 266 ${command} "${ci}"' 267 '"${cond}"' { 268 gsub(/\x1b\[0m/, "\x1b[0m\x1b['"${ansi}"'") 269 printf "\x1b['"${ansi}"'%s\x1b[0m%s", $0, ORS 270 next 271 } 272 1 273 ' "$@"