From 455d79db130768a7fae8e17d222f49d1466e5b46 Mon Sep 17 00:00:00 2001 From: Tom Ryder Date: Sun, 4 Dec 2016 14:18:25 +1300 Subject: Add gwp(1) --- .gitignore | 1 + Makefile | 6 ++++-- README.markdown | 1 + bin/gwp.awk | 57 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ man/man1/gwp.1df | 23 +++++++++++++++++++++++ 5 files changed, 86 insertions(+), 2 deletions(-) create mode 100644 bin/gwp.awk create mode 100644 man/man1/gwp.1df diff --git a/.gitignore b/.gitignore index bd49f1fb..7bd19d59 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ bin/csmw bin/ddup +bin/gwp bin/han bin/mean bin/med diff --git a/Makefile b/Makefile index 1131af09..3f48b8d9 100644 --- a/Makefile +++ b/Makefile @@ -68,6 +68,7 @@ SENDMAIL := msmtp all : bin/csmw \ bin/ddup \ + bin/gwp \ bin/han \ bin/mean \ bin/med \ @@ -87,6 +88,7 @@ clean distclean : rm -f \ bin/csmw \ bin/ddup \ + bin/gwp \ bin/han \ bin/mean \ bin/med \ @@ -185,8 +187,8 @@ install-bash-completion : install-bash install -pm 0644 -- bash/bash_completion "$(HOME)"/.config/bash_completion install -pm 0644 -- bash/bash_completion.d/* "$(HOME)"/.bash_completion.d -install-bin : bin/csmw bin/ddup bin/han bin/mean bin/med bin/mftl bin/mode \ - bin/rfct bin/rndi bin/sd2u bin/slsf bin/su2d bin/tot bin/unf \ +install-bin : bin/csmw bin/ddup bin/gwp bin/han bin/mean bin/med bin/mftl \ + bin/mode bin/rfct bin/rndi bin/sd2u bin/slsf bin/su2d bin/tot bin/unf \ install-bin-man install -m 0755 -d -- "$(HOME)"/.local/bin for name in bin/* ; do \ diff --git a/README.markdown b/README.markdown index fc248800..5eae69ac 100644 --- a/README.markdown +++ b/README.markdown @@ -444,6 +444,7 @@ Installed by the `install-bin` target: * `grc(1df)` quietly tests whether the given directory appears to be a Git repository with pending changes. * `gscr(1df)` scrubs Git repositories. +* `gwp(1df)` searches for alphanumeric words in a similar way to `grep(1)`. * `han(1df)` provides a `keywordprg` for Vim's Bash script filetype that will look for `help` topics. You could use it from the shell too. * `igex(1df)` wraps around a command to allow you to ignore error conditions diff --git a/bin/gwp.awk b/bin/gwp.awk new file mode 100644 index 00000000..db2764ec --- /dev/null +++ b/bin/gwp.awk @@ -0,0 +1,57 @@ +#!/usr/bin/awk -f +# Search for alphanumeric words in a file +BEGIN { + + # Name self + self = "gwp" + + # Words are separated by any non-alphanumeric character + FS = "[^[:alnum:]]" + + # First argument is the word required; push its case downward so we can + # match case-insensitively + word = tolower(ARGV[1]) + + # Blank the first argument so Awk doesn't try to read data from it as a file + ARGV[1] = "" + + # Bail out if we don't have a suitable word + if (!word) + fail("Need a single non-null alphanumeric string as a search word") + if (word ~ FS) + fail("Word contains non-alphanumeric characters; use grep(1)") +} + +# Bailout function +function fail(str) { + printf "%s: %s\n", self, str > "/dev/stderr" + exit(1) +} + +# If there's more than one filename, precede the print of the current line with +# a filename, a colon, and a space, much like grep(1) does; otherwise just +# print it +function fnpr() { + if (ARGC > 3) + print FILENAME ":" OFS $0 + else + print +} + +# Iterate through the words on this line and if any of them match our word, +# print the line, and flag that we've found at least one word; once a single +# instance of the word is found, just print and continue on to the next line +{ + for (i = 1; i <= NF; i++) { + if (tolower($i) == word) { + found = 1 + fnpr() + break + } + } +} + +# Exit zero if we found at least one match, non-zero otherwise +END { + exit(!found) +} diff --git a/man/man1/gwp.1df b/man/man1/gwp.1df new file mode 100644 index 00000000..c84cc12c --- /dev/null +++ b/man/man1/gwp.1df @@ -0,0 +1,23 @@ +.TH GWP 1df "December 2016" "Manual page for gwp" +.SH NAME +.B gwp +\- wordwise (alphanumeric) grep(1) +.SH SYNOPSIS +.B gwp WORD [FILE...] +.br +.SH DESCRIPTION +.B gwp +searches for complete alphanumeric words (not regular expressions) in the input and +prints the line if found. This means you can search for "test" and it won't +print lines just because they contain "latest". It's good for searching prose +or poetry rather than code. +.P +This is intended as a workaround for the absence of a portable implementation +of "word boundaries" in POSIX. Instead, this awk(1) script breaks each line +down into alphanumeric words and tests each one for case-insensitive equality. +.P +It does not emulate all of grep(1)'s features by any means, but does include +the feature of prefixing a matched line with the filename if more than one +filename was searched. +.SH AUTHOR +Tom Ryder -- cgit v1.2.3