]> Pileus Git - ~andy/sfvlug/commitdiff
Add sed and awk presentation
authorAndy Spencer <andy753421@gmail.com>
Sat, 16 Mar 2013 23:55:30 +0000 (23:55 +0000)
committerAndy Spencer <andy753421@gmail.com>
Sat, 16 Mar 2013 23:55:30 +0000 (23:55 +0000)
24 files changed:
.gitignore [new file with mode: 0644]
awk/ext/mkfile [new file with mode: 0644]
awk/ext/select.awk [new file with mode: 0644]
awk/ext/select.c [new file with mode: 0644]
awk/sedawk.pdf [new file with mode: 0644]
awk/sedawk.tex [new file with mode: 0644]
awk/src/awk-0-simpleawk.sh [new file with mode: 0755]
awk/src/awk-1-sum [new file with mode: 0755]
awk/src/awk-2-avg [new file with mode: 0755]
awk/src/awk-3-awklife.sh [new file with mode: 0755]
awk/src/awk-4-vcutfile.sh [new file with mode: 0755]
awk/src/awk-5-vgetparam.sh [new file with mode: 0755]
awk/src/awk-6-vlist.sh [new file with mode: 0755]
awk/src/awk-7-vstat.sh [new file with mode: 0755]
awk/src/challenge.awk [new file with mode: 0755]
awk/src/sed-0-simplesed.sh [new file with mode: 0755]
awk/src/sed-1-branching.sh [new file with mode: 0755]
awk/src/sed-2-fizzbuzz.sh [new file with mode: 0755]
awk/src/sed-3-sedlife.sh [new file with mode: 0755]
awk/src/sed-4-rhsed.sh [new file with mode: 0755]
awk/src/test.sh [new file with mode: 0644]
awk/src/test.txt [new file with mode: 0644]
awk/src/vpaste.sh [new file with mode: 0755]
awk/xkcd.png [new file with mode: 0644]

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..0c0b127
--- /dev/null
@@ -0,0 +1,16 @@
+# Misc
+*~
+*.swp
+
+# C output
+*.o
+*.a
+
+# Latex output
+*.aux
+*.log
+*.nav
+*.out
+*.snm
+*.toc
+*.vrb
diff --git a/awk/ext/mkfile b/awk/ext/mkfile
new file mode 100644 (file)
index 0000000..1171fc6
--- /dev/null
@@ -0,0 +1,14 @@
+CFLAGS   = -g -Wall -fPIC --std=gnu99
+CPPFLAGS = -I/usr/include/awk -I. -DHAVE_CONFIG_H
+
+test:Q: select.so
+       awk -f select.awk
+       #awk -f rhawk < testirc.txt
+       #awk -f rhawk < testirc.txt
+       #awk -f test.awk test.txt | awk -f rhawk #| grep 'points\|bid\|took'
+
+%.so: %.o
+       gcc $CFLAGS -shared -o $target $prereq $LDFLAGS
+
+%.o: %.c
+       gcc $CPPFLAGS $CFLAGS -c -o $target $prereq
diff --git a/awk/ext/select.awk b/awk/ext/select.awk
new file mode 100644 (file)
index 0000000..5b45a7a
--- /dev/null
@@ -0,0 +1,33 @@
+BEGIN {
+       extension("./select.so", "dlload");
+
+       nc0   = "netcat -l -p 12345"
+       nc1   = "netcat -l -p 54321"
+       stdin = "/dev/stdin"
+
+       while (1) {
+               # Open pipes
+               printf "" |& nc0
+               printf "" |& nc1
+
+               # Wait for input 
+               if (!(fd = select("from", stdin, nc0, nc1))) {
+                       print "timeout"
+                       continue
+               }
+
+               # Read a line
+               if (fd == stdin)
+                       if (!(st = getline line < fd))
+                               exit 0
+               if (fd == nc0 || fd == nc1)
+                       if (!(st = fd |& getline line)) {
+                               print "broken pipe"
+                               close(fd)
+                               continue
+                       }
+
+               # Print output
+               print "line: [" fd "] -> [" line "]"
+       }
+}
diff --git a/awk/ext/select.c b/awk/ext/select.c
new file mode 100644 (file)
index 0000000..d379167
--- /dev/null
@@ -0,0 +1,149 @@
+/*
+ * select.c - Provide select functions for gawk.
+ */
+
+/*
+ * Copyright (C) 2012 Andy Spencer
+ *
+ * GAWK 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.
+ *
+ * GAWK 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
+ */
+
+#include "awk.h"
+
+int plugin_is_GPL_compatible;
+
+/* Select function:
+ *   select(how, [timeout,] fd, ..)
+ *   type = {to,from,error,any} */
+static NODE *do_select(int nargs)
+{
+       /* Parse arguments */
+       if (do_lint && get_curfunc_arg_count() < 2)
+               lintwarn("select: not enough arguments");
+
+       /* - check how */
+       int read = 0, write = 0, except = 0;
+       NODE *node = get_scalar_argument(0, FALSE);
+       NODE *how  = force_string(node);
+       if (!strcmp("to",    how->stptr)) write  = 1;
+       if (!strcmp("from",  how->stptr)) read   = 1;
+       if (!strcmp("error", how->stptr)) except = 1;
+       if (!strcmp("any",   how->stptr)) read = write = except = 1;
+       if (!read && !write && !except) {
+               printf("select: invalid select type: %.*s\n",
+                               how->stlen, how->stptr);
+               return make_number((AWKNUM) -EINVAL);
+       }
+
+       /* - check timeout */
+       int    first = 1;
+       struct timeval _timeout = {.tv_sec = 1, .tv_usec = 0};
+       struct timeval *timeout = &_timeout;
+       NODE *next = get_scalar_argument(1, FALSE);
+       if (next->type == Node_val && next->flags & NUMBER) {
+               AWKNUM num = force_number(next);
+               if (num < 0) {
+                       timeout  = NULL;
+               } else {
+                       _timeout.tv_sec  = (int)num;
+                       _timeout.tv_usec = (num - (int)num) * 1E6;
+                       printf("timeout -> %lf %ld,%ld\n", num,
+                                       _timeout.tv_sec,
+                                       _timeout.tv_usec);
+               }
+               first = 2;
+       }
+
+       /* Clear fds */
+       int nfds = 0;
+       fd_set readfds, writefds, exceptfds;
+       FD_ZERO(&readfds);
+       FD_ZERO(&writefds);
+       FD_ZERO(&exceptfds);
+
+       /* Set fds */
+       for (int i = first; i < nargs; i++) {
+               NODE *node = get_scalar_argument(i, TRUE);
+               if (node == NULL)
+                       continue;
+               NODE *str  = force_string(node);
+               struct redirect *redir =
+                       getredirect(str->stptr, str->stlen);
+               if (redir == NULL) {
+                       int err = 0;
+                       int type = read && write ? redirect_twoway :
+                                  read          ? redirect_input  :
+                                  write         ? redirect_output : 0 ;
+                       redir = redirect(str, type, &err);
+               }
+               if (redir == NULL) {
+                       lintwarn("select: arg %d is not a redirect", i);
+                       continue;
+               }
+               if ((read  || except) && redir->iop->fd >= 0) {
+                       int fd = redir->iop->fd;
+                       if (read)      FD_SET(fd, &readfds);
+                       if (except)    FD_SET(fd, &exceptfds);
+                       if (fd > nfds) nfds = fd;
+               }
+               if ((write || except) && redir->fp) {
+                       int fd = fileno(redir->fp);
+                       if (write)     FD_SET(fd, &writefds);
+                       if (except)    FD_SET(fd, &exceptfds);
+                       if (fd > nfds) nfds = fd;
+               }
+       }
+
+       /* Select fds */
+       int rval = select(nfds+1, &readfds, &writefds, &exceptfds, timeout);
+       if (rval == 0)
+               return make_number((AWKNUM) 0);
+       if (rval == -1)
+               return make_number((AWKNUM) 0);
+
+       /* Return */
+       for (int i = first; i < nargs; i++) {
+               NODE *node = get_scalar_argument(i, TRUE);
+               if (node == NULL)
+                       continue;
+               NODE *str  = force_string(node);
+               struct redirect *redir =
+                       getredirect(str->stptr, str->stlen);
+               if (redir == NULL)
+                       continue;
+               if ((read  || except) && redir->iop->fd >= 0) {
+                       int fd = redir->iop->fd;
+                       if ((read   && FD_ISSET(fd, &readfds))  ||
+                           (except && FD_ISSET(fd, &writefds)))
+                               return node;
+               }
+               if ((write || except) && redir->fp) {
+                       int fd = fileno(redir->fp);
+                       if ((write  && FD_ISSET(fd, &writefds)) ||
+                           (except && FD_ISSET(fd, &exceptfds)))
+                               return node;
+               }
+       }
+
+       /* Error */
+       return make_number((AWKNUM) 0);
+}
+
+/* Load select function */
+NODE *dlload(NODE *tree, void *dl)
+{
+       make_builtin("select", do_select, 99);
+       return make_number((AWKNUM) 0);
+}
diff --git a/awk/sedawk.pdf b/awk/sedawk.pdf
new file mode 100644 (file)
index 0000000..35a44bb
Binary files /dev/null and b/awk/sedawk.pdf differ
diff --git a/awk/sedawk.tex b/awk/sedawk.tex
new file mode 100644 (file)
index 0000000..1a10104
--- /dev/null
@@ -0,0 +1,404 @@
+\documentclass{beamer}
+
+%%%%%%%%%%%%%%%%%%%
+% Commands/macros %
+%%%%%%%%%%%%%%%%%%%
+\newcommand{\link}[1]{
+  \begin{flushright}
+    \scriptsize{#1}
+  \end{flushright}
+}
+
+%%%%%%%%%%%%%%%%
+% Header/theme %
+%%%%%%%%%%%%%%%%
+%\usetheme[
+%  pageofpages=of,
+%  alternativetitlepage=true,
+%]{Torino}
+%\setbeamertemplate{footline}{}
+\setbeamersize{text margin left=20mm} 
+\setbeamersize{text margin right=10mm} 
+
+% Import packages
+\usepackage[english]{babel}
+\usepackage[latin1]{inputenc}
+\usepackage{times}
+\usepackage[T1]{fontenc}
+\usepackage{graphics}
+\usepackage{hyperref}
+\usepackage{ulem}
+\usepackage{listings}
+
+%%%%%%%%%%%%%%%%%%%%
+% Title page setup %
+%%%%%%%%%%%%%%%%%%%%
+\subject{%
+  sed,
+  awk
+}
+
+\keywords{%
+  sed,
+  awk,
+  grep,
+  unix,
+}
+
+\title[Sed and Awk]{%
+  Introduction to Sed and Awk scripting
+}
+
+\author[Spencer]{%
+  Andy Spencer
+}
+
+\date[2013-02-02]{%
+  February 2, 2013 \\
+  \small{San Fernando Valley Linux Users Group}
+}
+
+%%%%%%%%%%%%%%%%%
+% Content pages %
+%%%%%%%%%%%%%%%%%
+% Structure:
+%   - intro
+%     - perl/python
+%     - gnu tools only
+%   - history
+%     - ed
+%     - grep
+%     - tr
+%     - regular expressions
+%   - sed
+%     - sample command (s/foo/bar/)
+%     - command structure
+%     - other commands
+%     - addresses and ranges
+%     - branching
+%     - the hold space
+%     - fizz buzz
+%   - awk
+%     - sample command
+%       - hello world
+%       - sum
+%       - average 
+%     - command structure
+%       - patterns 
+%       - actions
+%     - record and fields
+%     - command line arguments
+%     - awk quirks (default values, string concat)
+%     - vpaste examples
+%       - get_param
+%       - cut_file
+%       - stat
+%       - head
+%       - beer
+%       - cowlife
+%     - programming language
+%       - variables, arrays
+%       - statements
+%       - operators
+%       - builtin functions
+%         - string manipulation
+%         - file/command I/O, networking
+%       - function definition
+%         - local variables
+%       - GNU extensions
+
+\begin{document}
+
+%%%%%%%%%%%%%%%%
+% Introduction %
+%%%%%%%%%%%%%%%%
+
+% intro
+% - perl/python
+% - gnu tools only
+% history
+% - ed
+% - grep
+% - tr
+% - regular expressions
+
+\begin{frame}[plain]
+  \titlepage
+\end{frame}
+
+\section{Introduction}
+\begin{frame}
+  \begin{quote}
+    One tool for one job?
+  \end{quote}
+  \begin{quote}
+    Those days are dead and gone and the eulogy was delivered by \sout{Perl}
+    \textrm{Python}.'' -Rob Pike
+  \end{quote}
+\end{frame}
+
+\begin{frame}[fragile]{When to use sed and awk?}
+  When to use sed?
+  \begin{itemize}
+    \item When you are ``editing'' a file
+    \item Short programs 1-5 lines
+  \end{itemize}
+  \ \par
+  When to use awk?
+  \begin{itemize}
+    \item When you need to ``summarize'' a file
+    \item Slightly longer programs 5-50 lines
+  \end{itemize}
+\end{frame}
+
+\begin{frame}[fragile]{When not to use them?}
+  \begin{itemize}
+    \item For longer program, use a programming language
+      \begin{itemize}
+        \item Awk lacks type checking, etc
+      \end{itemize}
+    \item For some very simple things
+      \begin{itemize}
+        \item grep, tr, seq
+        \item Unix shell expansion \$\{var/from/to\}
+        \item Fancy editor commands (vim, emacs)
+      \end{itemize}
+  \end{itemize}
+\end{frame}
+
+%\begin{frame}[fragile]{History}
+%\end{frame}
+
+
+%%%%%%%%%%%%%%%
+% Sed Sed Sed %
+%%%%%%%%%%%%%%%
+
+% - sample command (s/foo/bar/)
+% - command structure
+% - other commands
+% - addresses and ranges
+% - branching
+% - the hold space
+% - fizz buzz
+
+\begin{frame}[fragile]{Sed - simple commands}
+  Example
+\end{frame}
+
+\begin{frame}[fragile]{commands}
+  \begin{itemize}
+    \item[s] regular expression find/replace
+    \item[y] translate characters (like tr)
+    \item[p, P] print out the current line
+    \item[i, a] insert or append text
+    \item[c]    change line
+    \item[n, N] read the next line of input
+    \item[q, Q] exit/quit
+    \item[r, R, w, W] read/write files
+    \item[b, t, T] branch to label
+    \item[d, D] delete pattern space
+    \item[h, H, g, G, x] work with the pattern and hold spaces
+  \end{itemize}
+\end{frame}
+
+\begin{frame}[fragile]{addresses and ranges}
+  \begin{itemize}
+    \item[number]     match a line number
+    \item[\$]          the last line
+    \item[/rege/]     match a regular expression (not the same as s///)
+    \item[first~step] match every step'th line starting with first
+    \item[0,addr]     match every step'th line starting with first
+    \item[addr,+N]    address addr and N following lines
+    \item[addr,~N]    match addr and lines up to a multiple of N 
+  \end{itemize}
+\end{frame}
+
+\begin{frame}[fragile]{branching}
+  \begin{itemize}
+    \item Can be used for loops
+    \item Skipping when a pattern fails
+    \item I rarely use these
+  \end{itemize}
+\end{frame}
+
+\begin{frame}[fragile]{the hold space}
+  \begin{itemize}
+    \item Can be used for loops
+    \item Skipping when a pattern fails
+    \item Can be used like a variable
+    \item Also rarely used
+  \end{itemize}
+\end{frame}
+
+\begin{frame}[fragile]{fizz buzz}
+  Example
+\end{frame}
+
+%%%%%%%%%%%%%%%
+% Awk Awk Awk %
+%%%%%%%%%%%%%%%
+
+% sample command
+% - hello world
+% - sum
+% - average 
+% command structure
+% - patterns 
+% - actions
+% record and fields
+% command line arguments
+% awk quirks (default values, string concat)
+% vpaste examples
+% - get_param
+% - cut_file
+% - stat
+% - head
+% - beer
+% - cowlife
+% programming language
+% - variables, arrays
+% - statements
+% - operators
+% - builtin functions
+%   - string manipulation
+%   - file/command I/O, networking
+% - function definition
+%   - local variables
+% - GNU extensions
+
+\begin{frame}[fragile]{Awk - simple commands}
+  Example
+\end{frame}
+
+\begin{frame}[fragile]{Command structure}
+  Basic awk scripts consist of patterns and actions
+
+  When a pattern matches, the action is executed
+
+  Some special patterns: BEGIN, END, BEGINFILE, ENDFILE
+  \begin{lstlisting}
+    PATTERN { ACTION }
+    PATTERN { ACTION }
+  \end{lstlisting}
+\end{frame}
+
+\begin{frame}[fragile]{Records and fields}
+  Text is split twice when reading the file
+
+  Patterns are matched against records
+
+  Fields can be accessed using \$N
+
+  \
+  \par
+  \begin{itemize}
+    \item[Records] by default, a line, changed using RS
+    \item[Fields] by default, a word ina line, changed using FS
+  \end{itemize}
+\end{frame}
+
+\begin{frame}[fragile]{Command line arguments}
+  \begin{itemize}
+    \item[-v] Set a variable (var=val)
+    \item[-F] Change field separator, can also be done from BEGIN
+  \end{itemize}
+  \begin{lstlisting}
+    awk -v 'var=$VAR' '{ script }
+  \end{lstlisting}
+\end{frame}
+
+\begin{frame}[fragile]{Awk quirks}
+  \begin{itemize}
+    \item default values are 0, no need for declaration
+    \item string concatonation is implicit
+  \end{itemize}
+\end{frame}
+
+\begin{frame}[fragile]{vpaste examples - get param}
+  Example
+\end{frame}
+
+\begin{frame}[fragile]{vpaste examples - cut file}
+  Example
+\end{frame}
+
+\begin{frame}[fragile]{vpaste examples - stat}
+  Example
+\end{frame}
+
+\begin{frame}[fragile]{vpaste examples - head}
+  Example
+\end{frame}
+
+\begin{frame}[fragile]{vpaste examples - cowlife}
+  Example
+\end{frame}
+
+\begin{frame}[fragile]{awk as a programming language}
+  \begin{itemize}
+    \item built-in functions
+    \item user defined functions
+    \item variables
+    \item file i/o
+    \item networking
+  \end{itemize}
+\end{frame}
+
+\begin{frame}[fragile]{Variables and arrays}
+\end{frame}
+
+\begin{frame}[fragile]{Statements}
+  \begin{itemize}
+    \item if (condition) body [ else body ]
+    \item while (condition) body
+    \item for (i=0; i<10; i++) body
+    \item for (i in array) body
+    \item break, continue
+    \item delete var, delete array[index]
+    \item swtich (expr) { case value: body; default: body }
+  \end{itemize}
+\end{frame}
+
+\begin{frame}[fragile]{Builtin functions}
+  \begin{itemize}
+    \item[Math] atan2, cos, exp, int, log, rand, sin, sqrt, srand
+    \item[Strings] asort, gsub, length, match, split, sprintf
+    \item[Time] mktime, strftime, systime
+    \item[Bitwise] add, or, xor, etc
+  \end{itemize}
+\end{frame}
+
+\begin{frame}[fragile]{I/O and networking}
+  \begin{itemize}
+    \item next, nextfile, print, printf
+    \item system, fflush
+  \end{itemize}
+  Reading from files and commands
+  \begin{itemize}
+    \item getline [var] [<file]
+    \item command | getline [var]
+    \item command |\& getline [var]
+  \end{itemize}
+  Writing to files and commands
+  \begin{itemize}
+    \item print .. > > file
+    \item print .. | command
+    \item print .. |\& command
+  \end{itemize}
+\end{frame}
+
+\begin{frame}[fragile]{User defined functions}
+  \begin{lstlisting}
+    function sayhi(name,        str) {
+        str = "Hello, " name "!'
+        print str
+    }
+  \end{lstlisting}
+\end{frame}
+
+\begin{frame}[fragile]{GNU extensions}
+  Example
+\end{frame}
+
+\end{document}
diff --git a/awk/src/awk-0-simpleawk.sh b/awk/src/awk-0-simpleawk.sh
new file mode 100755 (executable)
index 0000000..f7609c9
--- /dev/null
@@ -0,0 +1,3 @@
+#!/bin/bash
+
+awk 'BEGIN { print "Hello, world" }'
diff --git a/awk/src/awk-1-sum b/awk/src/awk-1-sum
new file mode 100755 (executable)
index 0000000..981faad
--- /dev/null
@@ -0,0 +1,4 @@
+#!/bin/awk -f
+BEGIN { RS="[^0-9eE.+-]" }
+//    { sum += $0 }
+END   { print sum }
diff --git a/awk/src/awk-2-avg b/awk/src/awk-2-avg
new file mode 100755 (executable)
index 0000000..342a65e
--- /dev/null
@@ -0,0 +1,4 @@
+#!/bin/awk -f
+BEGIN   { RS="[^0-9eE.+-]+" }
+/[0-9]/ { sum += $0; cnt++ }
+END     { print sum / cnt }
diff --git a/awk/src/awk-3-awklife.sh b/awk/src/awk-3-awklife.sh
new file mode 100755 (executable)
index 0000000..2bc4cf1
--- /dev/null
@@ -0,0 +1,74 @@
+#!/bin/bash
+
+frame="
+. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+. . . . . . . . . . . . . . . . . . . . . . . . . # . . . . . . . . . . . .
+. . . . . . . . . . . . . . . . . . . . . . . # . # . . . . . . . . . . . .
+. . . . . . . . . . . . . # # . . . . . . # # . . . . . . . . . . . . # # .
+. . . . . . . . . . . . # . . . # . . . . # # . . . . . . . . . . . . # # .
+. # # . . . . . . . . # . . . . . # . . . # # . . . . . . . . . . . . . . .
+. # # . . . . . . . . # . . . # . # # . . . . # . # . . . . . . . . . . . .
+. . . . . . . . . . . # . . . . . # . . . . . . . # . . . . . . . . . . . .
+. . . . . . . . . . . . # . . . # . . . . . . . . . . . . . . . . . . . . .
+. . . . . . . . . . . . . # # . . . . . . . . . . . . . . . . . . . . . . .
+. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+"
+
+while sleep 0.05; do
+       echo "$frame" | cowsay -n
+       frame=$(echo "$frame" | awk '
+               function count(i) {
+                       cnt = 0;
+                       if (tops[i-1] == "#") cnt++;
+                       if (tops[i  ] == "#") cnt++;
+                       if (tops[i+1] == "#") cnt++;
+
+                       if (curs[i-1] == "#") cnt++;
+                       if (curs[i+1] == "#") cnt++;
+
+                       if (bots[i-1] == "#") cnt++;
+                       if (bots[i  ] == "#") cnt++;
+                       if (bots[i+1] == "#") cnt++;
+                       return cnt;
+               }
+
+               function run() {
+                       split(top, tops, " ")
+                       split(cur, curs, " ")
+                       split(bot, bots, " ")
+                       len = length(curs);
+                       for (i=1; i < len+1; i++) {
+                               new = curs[i]
+                               cnt = count(i)
+                               if (cnt <  2) new = ".";
+                               if (cnt == 3) new = "#";
+                               if (cnt >  3) new = ".";
+                               printf "%s%s", new, i==len ? "" : " "
+                       }
+                       print ""
+               }
+
+               // {
+                       top=cur; cur=bot; bot=$0
+                       if (cur) run()
+               }
+
+               END {
+                       top=cur; cur=bot; bot="";
+                       run();
+               }
+       ')
+done
diff --git a/awk/src/awk-4-vcutfile.sh b/awk/src/awk-4-vcutfile.sh
new file mode 100755 (executable)
index 0000000..3ca4a72
--- /dev/null
@@ -0,0 +1,22 @@
+#!/bin/bash
+
+# cut file
+bnd="${CONTENT_TYPE/*boundary\=/}"
+
+awk -v "want=$1" -v "bnd=$bnd" '
+       BEGIN { RS="\r\n" }
+
+       # reset based on boundaries
+       $0 == "--"bnd""     { st=1; next; }
+       $0 == "--"bnd"--"   { st=0; next; }
+       $0 == "--"bnd"--\r" { st=0; next; }
+
+       # search for wanted file
+       st == 1 && $0 ~  "^Content-Disposition:.* name=\""want"\"" { st=2; next; }
+       st == 1 && $0 == "" { st=9; next; }
+
+       # wait for newline, then start printing
+       st == 2 && $0 == "" { st=3; next; }
+       st == 3             { print $0    }
+       # head
+' | head -c $((128*1024)) # Limit size to 128K
diff --git a/awk/src/awk-5-vgetparam.sh b/awk/src/awk-5-vgetparam.sh
new file mode 100755 (executable)
index 0000000..0798e2e
--- /dev/null
@@ -0,0 +1,9 @@
+#!/bin/bash
+
+# get param
+awk -v "key=member" '
+       BEGIN {RS=" "; FS="="}
+       $1 ~ key {print $2}
+' <<-EOF
+       name=andy member=sfvlug
+EOF
diff --git a/awk/src/awk-6-vlist.sh b/awk/src/awk-6-vlist.sh
new file mode 100755 (executable)
index 0000000..a055424
--- /dev/null
@@ -0,0 +1,12 @@
+#!/bin/bash
+
+# List
+awk -v 'rows=4' -v 'cols=60' '
+       FNR==1      { gsub(/.*\//, "", FILENAME);
+                     print FILENAME
+                     print "-----" }
+       FNR==1,/^$/ { next }
+       /\S/        { i++; printf "%."cols"s\n", $0 }
+       i>=rows     { nextfile  }
+       ENDFILE     { i=0; print ""  }
+' $(ls -t db/*)
diff --git a/awk/src/awk-7-vstat.sh b/awk/src/awk-7-vstat.sh
new file mode 100755 (executable)
index 0000000..886152b
--- /dev/null
@@ -0,0 +1,12 @@
+#!/bin/bash
+
+# Stat
+ls -l --time-style='+%Y %m' db |
+awk -v 'hdr=Jan  Feb  Mar  Apr  May  Jun  Jul  Aug  Sep  Oct  Nov  Dec' '
+       BEGIN { printf "%64s\n", hdr }
+       NR>1  { cnt[$6+0][$7+0]++ }
+       END   { for (y in cnt) {
+                 printf "%4d", y
+                 for (m=1; m<=12; m++)
+                   printf "%5s", cnt[y][m]
+                 printf "\n" } }'
diff --git a/awk/src/challenge.awk b/awk/src/challenge.awk
new file mode 100755 (executable)
index 0000000..b613750
--- /dev/null
@@ -0,0 +1,46 @@
+#!/bin/awk -f
+
+function connect(method)
+{
+       HOST = "ctf.nullcon.net"
+       FILE = "/inet/tcp/0/" HOST "/80"
+       PATH = "/challenges/programming/challenge.php"
+
+       print method " " PATH " HTTP/1.0" |& FILE
+       print "Host: " HOST ""            |& FILE
+
+       return FILE
+}
+
+
+BEGIN {
+       sock = connect("GET")
+       print |& sock
+       close(sock, "to")
+       while (sock |& getline line) {
+               if (match(line, "Set-Cookie:"))
+                       cookie = line
+               if (match(line, "span"))
+                       text = line
+       }
+       close(sock)
+
+       gsub("&nbsp;",    " ", text)
+       gsub("<[^>]*>",   " ", text)
+       gsub("^ *| *$",   "",  text)
+       gsub("  +",       "+", text)
+       gsub("^[^:]*: *", "",  cookie)
+       gsub(" *;.*",     "",  cookie)
+
+       sock = connect("POST")
+       resp = "answer=" text "&submit=Submit"
+       print "Content-Type: application/x-www-form-urlencoded" |& sock
+       print "Content-Length: " length(resp) |& sock
+       print "Cookie: " cookie |& sock
+       print |& sock
+       print resp |& sock
+       close(sock, "to")
+       while (sock |& getline line)
+               print line
+       close(sock)
+}
diff --git a/awk/src/sed-0-simplesed.sh b/awk/src/sed-0-simplesed.sh
new file mode 100755 (executable)
index 0000000..eac4879
--- /dev/null
@@ -0,0 +1,7 @@
+#!/bin/bash
+
+sed 's/AUTHOR/Andy Spencer/'
+
+sed 's/AUTHOR/Andy Spencer/g'
+
+sed -f script.sed
diff --git a/awk/src/sed-1-branching.sh b/awk/src/sed-1-branching.sh
new file mode 100755 (executable)
index 0000000..93dce4a
--- /dev/null
@@ -0,0 +1,9 @@
+#!/bin/bash
+
+sed ':s; s/--$//; T; N; s/\n//; ts' <<-EOF
+       Hello, --
+       world!
+       My name --
+       is --
+       Andy.
+EOF
diff --git a/awk/src/sed-2-fizzbuzz.sh b/awk/src/sed-2-fizzbuzz.sh
new file mode 100755 (executable)
index 0000000..b3d88f4
--- /dev/null
@@ -0,0 +1,6 @@
+#!/bin/bash
+
+seq 100 |
+sed '0~15cFizzBuzz
+     0~05cBuzz
+     0~03cFizz'
diff --git a/awk/src/sed-3-sedlife.sh b/awk/src/sed-3-sedlife.sh
new file mode 100755 (executable)
index 0000000..b4f1407
--- /dev/null
@@ -0,0 +1,62 @@
+#!/bin/bash
+
+sed -nr '
+       # Buffer input
+       s/^/\n/
+       :s; N; $be; bs; :e
+       s/$/\n/
+       s/ +/         /g
+       s/ *\n/         \n/g
+
+       # Live!
+       :l
+       s/(\n#[^\n]*\n\S+ +[^ 1]+) /\11/g
+       s/(\n\S+ +#[^\n]*\n\S+ +[^ 2]+) /\12/g
+       s/(\n\S+ +\S+ +#[^\n]*\n\S+ +[^ 3]+) /\13/g
+       s/(\n#\S* +[^ 4]+) /\14/g
+       s/(\n\S+ +[^ 5]+) ( +#)/\15\2/g
+       s/(\n\S+ +[^ 6]+) ([^\n]*\n#)/\16\2/g
+       s/(\n\S+ +[^ 7]+) ([^\n]*\n\S+ +#)/\17\2/g
+       s/(\n\S+ +[^ 8]+) ([^\n]*\n\S+ +\S+ +#)/\18\2/g
+       tl
+       s/(\n)([^@\n ])([^@\n ]*)( +)([^\n]+)/\1\5\2@\3\4/g
+       tl
+
+       # Format output
+       s/@//g
+       s/#([0-9]{4,8}) /.\1 /g
+       s/[^0-9]([0-9]{3}) /#\1 /g
+       s/#([0-9]{0,1}) /.\1 /g
+       s/[0-9]/ /g
+
+       # Die!
+       s/ +/ /g;
+       p
+       s/ +/         /g
+       bl
+' <<EOF
+. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+. . . . . . . . . . . . . . . . . . . . . . . . . # . . . . . . . . . . . .
+. . . . . . . . . . . . . . . . . . . . . . . # . # . . . . . . . . . . . .
+. . . . . . . . . . . . . # # . . . . . . # # . . . . . . . . . . . . # # .
+. . . . . . . . . . . . # . . . # . . . . # # . . . . . . . . . . . . # # .
+. # # . . . . . . . . # . . . . . # . . . # # . . . . . . . . . . . . . . .
+. # # . . . . . . . . # . . . # . # # . . . . # . # . . . . . . . . . . . .
+. . . . . . . . . . . # . . . . . # . . . . . . . # . . . . . . . . . . . .
+. . . . . . . . . . . . # . . . # . . . . . . . . . . . . . . . . . . . . .
+. . . . . . . . . . . . . # # . . . . . . . . . . . . . . . . . . . . . . .
+. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+EOF
diff --git a/awk/src/sed-4-rhsed.sh b/awk/src/sed-4-rhsed.sh
new file mode 100755 (executable)
index 0000000..4949caf
--- /dev/null
@@ -0,0 +1,62 @@
+# Clear hold space
+x; s/.*//; x
+
+# Debug input
+s/^/< /
+w /dev/stderr
+s/^< //
+
+# Setup variables:
+s/[$=]/&\\/g
+s/\(:\([^ ]*\) \)\?\(\([^ ]*\) \)\(\([^ ]*\) \)\?\(:\(.*\)\)/AUTH= SERVER= NICK= CHANNEL= CMD=\4 SRC=\2 DST=\6 TO= FROM= MSG=\8/
+s/\(TO=\)\(.*MSG=\([^:,]\+\)[:,]\)/\1\3\2/
+s/\(SRC=\([^!]\+\)!.*\)\(FROM=\)/\1\3\2/
+s/CHANNEL=/&#rhnoise/
+s/NICK=/&rhsed/
+s/SERVER=/&irc.freenode.net/
+s/\(AUTH=\)\(.*TO=rhsed.*FROM=andy753421\)/\1yes\2/
+
+# IRC library commands
+1                         { x; s/$/\nUSER andy c $SERVER :$NICK/; x; }
+1                         { x; s/$/\nNICK rhsed/; x; }
+/CMD=PING/                { x; s/$/\nPING :$MSG/; x; }
+/CMD=001.*MSG=.*Welcome/  { x; s/$/\nJOIN $CHANNEL/; x; }
+
+# Bot commands
+/MSG=.*\<sed\>/           { x; s/$/\n.say Sed!/; x; }
+/NICK=\([^ ]*\).*MSG=\1:/ { x; s/$/\n.say Hello, $FROM/; x; }
+/MSG=.dup/                { x; s/$/\n.say Dup! $MSG/; x; }
+/MSG=.ping/               { x; s/$/\n.reply Pong!/; x; }
+/AUTH=yes.*MSG=.*die in a fire/Q
+
+# Helper functions
+x
+s/\n.reply /\n.say $FROM: /g
+s/\n.say *\([^\n]*\)/\nPRIVMSG #rhnoise :\1/g
+x
+
+# Replace variables
+G
+:vars
+s/\(.*SERVER=\([^ ]*\).*\n.*\)\$SERVER/\1\2/
+s/\(.*NICK=\([^ ]*\).*\n.*\)\$NICK/\1\2/
+s/\(.*CHANNEL=\([^ ]*\).*\n.*\)\$CHANNEL/\1\2/
+s/\(.*CMD=\([^ ]*\).*\n.*\)\$CMD/\1\2/
+s/\(.*SRC=\([^ ]*\).*\n.*\)\$SRC/\1\2/
+s/\(.*DST=\([^ ]*\).*\n.*\)\$DST/\1\2/
+s/\(.*TO=\([^ ]*\).*\n.*\)\$TO/\1\2/
+s/\(.*FROM=\([^ ]*\).*\n.*\)\$FROM/\1\2/
+s/\(.*MSG=\([^\n]*\)\n.*\)\$MSG/\1\2/
+t vars
+
+## Output
+s/^[^\n]*\n*//
+s/\([$=]\)\\/\1/g
+/./ {
+       w /dev/stdout
+       s/\(^\|\n\)/\1> /g
+       w /dev/stderr
+}
+d
+
+# vim: ft=sed
diff --git a/awk/src/test.sh b/awk/src/test.sh
new file mode 100644 (file)
index 0000000..849a391
--- /dev/null
@@ -0,0 +1,15 @@
+#!/bin/bash
+
+awk '
+       function hello(name,    str) {
+               str = "hello, " name
+               print str
+       }
+       function call(fun, arg) {
+               @fun(arg);
+       }
+       BEGIN {
+               fun = "hello";
+               call(fun, "Andy");
+       }
+'
diff --git a/awk/src/test.txt b/awk/src/test.txt
new file mode 100644 (file)
index 0000000..f00c965
--- /dev/null
@@ -0,0 +1,10 @@
+1
+2
+3
+4
+5
+6
+7
+8
+9
+10
diff --git a/awk/src/vpaste.sh b/awk/src/vpaste.sh
new file mode 100755 (executable)
index 0000000..c7b4aca
--- /dev/null
@@ -0,0 +1,48 @@
+#get param
+awk -v "key=$1" '
+       BEGIN {RS=" "; FS="="}
+       $1 ~ key {print $2}
+'
+
+# cut file
+bnd="${CONTENT_TYPE/*boundary\=/}"
+
+awk -v "want=$1" -v "bnd=$bnd" '
+       BEGIN { RS="\r\n" }
+
+       # reset based on boundaries
+       $0 == "--"bnd""     { st=1; next; }
+       $0 == "--"bnd"--"   { st=0; next; }
+       $0 == "--"bnd"--\r" { st=0; next; }
+
+       # search for wanted file
+       st == 1 && $0 ~  "^Content-Disposition:.* name=\""want"\"" { st=2; next; }
+       st == 1 && $0 == "" { st=9; next; }
+
+       # wait for newline, then start printing
+       st == 2 && $0 == "" { st=3; next; }
+       st == 3             { print $0    }
+       # head
+' | head -c $((128*1024)) # Limit size to 128K
+
+# List
+awk -v 'rows=4' -v 'cols=60' '
+       FNR==1      { gsub(/.*\//, "", FILENAME);
+                     print FILENAME
+                     print "-----" }
+       FNR==1,/^$/ { next }
+       /\S/        { i++; printf "%."cols"s\n", $0 }
+       i>=rows     { nextfile  }
+       ENDFILE     { i=0; print ""  }
+' $(ls -t db/*)
+
+# Stat
+ls -l --time-style='+%Y %m' db |
+awk -v 'hdr=Jan  Feb  Mar  Apr  May  Jun  Jul  Aug  Sep  Oct  Nov  Dec' '
+       BEGIN { printf "%64s\n", hdr }
+       NR>1  { cnt[$6+0][$7+0]++ }
+       END   { for (y in cnt) {
+                 printf "%4d", y
+                 for (m=1; m<=12; m++)
+                   printf "%5s", cnt[y][m]
+                 printf "\n" } }'
diff --git a/awk/xkcd.png b/awk/xkcd.png
new file mode 100644 (file)
index 0000000..acbc243
Binary files /dev/null and b/awk/xkcd.png differ