randint # randint - return random integer x, 1 <= x <= n randint randint function randint(n) { randint return int(n * rand()) + 1 randint } randlet # randlet - generate random lower-case letter randlet randlet function randlet() { randlet return substr("abcdefghijklmnopqrstuvwxyz", randint(26), 1) randlet } choose # choose - print in order k random elements from A[1]..A[n] choose choose function choose(A, k, n, i) { choose for (i = 1; n > 0; i++) choose if (rand() < k/n--) { choose print A[i] choose k-- choose } choose } comb.ans # print k distinct random integers between 1 and n comb.ans comb.ans { random($1, $2) } comb.ans comb.ans function random(k, n, A, i, r) { comb.ans for (i = n-k+1; i <= n; i++) comb.ans ((r = randint(i)) in A) ? A[i] : A[r] comb.ans for (i in A) comb.ans print i comb.ans } comb.ans comb.ans function randint(n) { return int(n*rand())+1 } bridge.ans # bridge - generate random bridge hands bridge.ans bridge.ans BEGIN { split(permute(52,52), deck) # generate a random deck bridge.ans sort(1,13); sort(14,26); sort(27,39); sort(40,52) # sort hands bridge.ans prhands() # format and print the four hands bridge.ans } bridge.ans bridge.ans function permute(k, n, i, p, r) { # generate a random permutation bridge.ans srand(); p = " " # of k integers between 1 and n bridge.ans for (i = n-k+1; i <= n; i++) bridge.ans if (p ~ " " (r = int(i*rand())+1) " " ) bridge.ans sub(" " r " ", " " r " " i " ", p) # put i after r in p bridge.ans else p = " " r p # put r at beginning of p bridge.ans return p bridge.ans } bridge.ans bridge.ans function sort(left,right, i,j,t) { # sort hand in deck[left..right] bridge.ans for (i = left+1; i <= right; i++) bridge.ans for (j = i; j > left && deck[j-1] < deck[j]; j--) { bridge.ans t = deck[j-1]; deck[j-1] = deck[j]; deck[j] = t bridge.ans } bridge.ans } bridge.ans bridge.ans function prhands() { # print the four hands bridge.ans b = sprintf("%20s", " "); b40 = sprintf("%40s", " ") bridge.ans card = 1 # global index into deck bridge.ans suits(13); print b " NORTH" bridge.ans print b spds; print b hrts; print b dnds; print b clbs bridge.ans suits(26) # create the west hand from deck[14..26] bridge.ans ws = spds substr(b40, 1, 40 - length(spds)) bridge.ans wh = hrts substr(b40, 1, 40 - length(hrts)) bridge.ans wd = dnds substr(b40, 1, 40 - length(dnds)) bridge.ans wc = clbs substr(b40, 1, 40 - length(clbs)) bridge.ans suits(39); print " WEST" sprintf("%36s", " ") "EAST" bridge.ans print ws spds; print wh hrts; print wd dnds; print wc clbs bridge.ans suits(52); print b " SOUTH" bridge.ans print b spds; print b hrts; print b dnds; print b clbs bridge.ans } bridge.ans bridge.ans function suits(j) { # collect suits of hand in deck[j-12..j] bridge.ans for (spds = "S:"; deck[card] > 39 && card <= j; card++) bridge.ans spds = spds " " fvcard(deck[card]) bridge.ans for (hrts = "H:"; deck[card] > 26 && card <= j; card++) bridge.ans hrts = hrts " " fvcard(deck[card]) bridge.ans for (dnds = "D:"; deck[card] > 13 && card <= j; card++) bridge.ans dnds = dnds " " fvcard(deck[card]) bridge.ans for (clbs = "C:"; card <= j; card++) bridge.ans clbs = clbs " " fvcard(deck[card]) bridge.ans } bridge.ans bridge.ans function fvcard(i) { # compute face value of card i bridge.ans if (i % 13 == 0) return "A" bridge.ans else if (i % 13 == 12) return "K" bridge.ans else if (i % 13 == 11) return "Q" bridge.ans else if (i % 13 == 10) return "J" bridge.ans else return (i % 13) + 1 bridge.ans } cliche # cliche - generate an endless stream of cliches cliche # input: lines of form subject:predicate cliche # output: lines of random subject and random predicate cliche cliche BEGIN { FS = ":" } cliche { x[NR] = $1; y[NR] = $2 } cliche END { for (;;) print x[randint(NR)], y[randint(NR)] } cliche cliche function randint(n) { return int(n * rand()) + 1 } grammar Sentence -> Nounphrase Verbphrase grammar Nounphrase -> the boy grammar Nounphrase -> the girl grammar Verbphrase -> Verb Modlist Adverb grammar Verb -> runs grammar Verb -> walks grammar Modlist -> grammar Modlist -> very Modlist grammar Adverb -> quickly grammar Adverb -> slowly sentgen # sentgen - random sentence generator sentgen # input: grammar file; sequence of nonterminals sentgen # output: a random sentence for each nonterminal sentgen sentgen BEGIN { # read rules from grammar file sentgen while (getline < "grammar" > 0) sentgen if ($2 == "->") { sentgen i = ++lhs[$1] # count lhs sentgen rhscnt[$1, i] = NF-2 # how many in rhs sentgen for (j = 3; j <= NF; j++) # record them sentgen rhslist[$1, i, j-2] = $j sentgen } else sentgen print "illegal production: " $0 sentgen } sentgen sentgen { if ($1 in lhs) { # nonterminal to expand sentgen gen($1) sentgen printf("\n") sentgen } else sentgen print "unknown nonterminal: " $0 sentgen } sentgen sentgen function gen(sym, i, j) { sentgen if (sym in lhs) { # a nonterminal sentgen i = int(lhs[sym] * rand()) + 1 # random production sentgen for (j = 1; j <= rhscnt[sym, i]; j++) # expand rhs's sentgen gen(rhslist[sym, i, j]) sentgen } else sentgen printf("%s ", sym) sentgen } sentgen1 # sentgen1 - random sentence generator with probabilities sentgen1 # input: grammar file; sequence of nonterminals sentgen1 # output: random sentences generated by the grammar sentgen1 sentgen1 BEGIN { # read rules from grammar file sentgen1 while (getline < "test-gram" > 0) sentgen1 if ($2 == "->") { sentgen1 i = ++lhs[$1] # count lhs sentgen1 rhsprob[$1, i] = $NF # 0 <= probability <= 1 sentgen1 rhscnt[$1, i] = NF-3 # how many in rhs sentgen1 for (j = 3; j < NF; j++) # record them sentgen1 rhslist[$1, i, j-2] = $j sentgen1 } else sentgen1 print "illegal production: " $0 sentgen1 for (sym in lhs) sentgen1 for (i = 2; i <= lhs[sym]; i++) sentgen1 rhsprob[sym, i] += rhsprob[sym, i-1] sentgen1 } sentgen1 sentgen1 { if ($1 in lhs) { # nonterminal to expand sentgen1 gen($1) sentgen1 printf("\n") sentgen1 } else sentgen1 print "unknown nonterminal: " $0 sentgen1 } sentgen1 sentgen1 function gen(sym, i, j) { sentgen1 if (sym in lhs) { # a nonterminal sentgen1 j = rand() # random production sentgen1 for (i = 1; i <= lhs[sym] && j > rhsprob[sym, i]; i++) sentgen1 ; sentgen1 for (j = 1; j <= rhscnt[sym, i]; j++) # expand rhs's sentgen1 gen(rhslist[sym, i, j]) sentgen1 } else sentgen1 printf("%s ", sym) sentgen1 } sentgen2 # sentgen2 - random sentence generator (nonrecursive) sentgen2 # input: grammar file; sequence of nonterminals sentgen2 # output: random sentences generated by the grammar sentgen2 sentgen2 BEGIN { # read rules from grammar file sentgen2 while (getline < "grammar" > 0) sentgen2 if ($2 == "->") { sentgen2 i = ++lhs[$1] # count lhs sentgen2 rhscnt[$1, i] = NF-2 # how many in rhs sentgen2 for (j = 3; j <= NF; j++) # record them sentgen2 rhslist[$1, i, j-2] = $j sentgen2 } else sentgen2 print "illegal production: " $0 sentgen2 } sentgen2 sentgen2 { if ($1 in lhs) { # nonterminal to expand sentgen2 push($1) sentgen2 gen() sentgen2 printf("\n") sentgen2 } else sentgen2 print "unknown nonterminal: " $0 sentgen2 } sentgen2 sentgen2 function gen( i, j) { sentgen2 while (stp >= 1) { sentgen2 sym = pop() sentgen2 if (sym in lhs) { # a nonterminal sentgen2 i = int(lhs[sym] * rand()) + 1 # random production sentgen2 for (j = rhscnt[sym, i]; j >= 1; j--) # expand rhs's sentgen2 push(rhslist[sym, i, j]) sentgen2 } else sentgen2 printf("%s ", sym) sentgen2 } sentgen2 } sentgen2 sentgen2 function push(s) { stack[++stp] = s } sentgen2 sentgen2 function pop() { return stack[stp--] } arith # arith - addition drill arith # usage: awk -f arith [ optional problem size ] arith # output: queries of the form "i + j = ?" arith arith BEGIN { arith maxnum = ARGC > 1 ? ARGV[1] : 10 # default size is 10 arith ARGV[1] = "-" # read standard input subsequently arith srand() # reset rand from time of day arith do { arith n1 = randint(maxnum) arith n2 = randint(maxnum) arith printf("%g + %g = ? ", n1, n2) arith while ((input = getline) > 0) arith if ($0 == n1 + n2) { arith print "Right!" arith break arith } else if ($0 == "") { arith print n1 + n2 arith break arith } else arith printf("wrong, try again: ") arith } while (input > 0) arith } arith arith function randint(n) { return int(rand()*n)+1 } quiz.elems symbol:number:name|element quiz.elems H:1:Hydrogen quiz.elems He:2:Helium quiz.elems Li:3:Lithium quiz.elems Be:4:Beryllium quiz.elems B:5:Boron quiz.elems C:6:Carbon quiz.elems N:7:Nitrogen quiz.elems O:8:Oxygen quiz.elems F:9:Fluorine quiz.elems Ne:10:Neon quiz.elems Na:11:Sodium|Natrium quiz.elems Mg:12:Magnesium quiz.elems Al:13:Aluminum quiz.elems Si:14:Silicon quiz.elems P:15:Phosphorus quiz.elems S:16:Sulphur|Sulfur quiz.elems Cl:17:Chlorine quiz.elems Ar:18:Argon quiz.elems K:19:Potassium|Kalium quiz.elems Ca:20:Calcium quiz.elems Sc:21:Scandium quiz.elems Ti:22:Titanium quiz.elems V:23:Vanadium quiz.elems Cr:24:Chromium quiz.elems Mn:25:Manganese quiz.elems Fe:26:Iron|Ferrum quiz.elems Co:27:Cobalt quiz.elems Ni:28:Nickel quiz.elems Cu:29:Copper|Cuprum quiz.elems Zn:30:Zinc quiz.elems Ga:31:Gallium quiz.elems Ge:32:Germanium quiz.elems As:33:Arsenic quiz.elems Se:34:Selenium quiz.elems Br:35:Bromine quiz.elems Kr:36:Krypton quiz.elems Rb:37:Rubidium quiz.elems Sr:38:Strontium quiz.elems Y:39:Yttrium quiz.elems Zr:40:Zirconium quiz.elems Nb:41:Niobium quiz.elems Mo:42:Molybdenum quiz.elems Tc:43:Technetium quiz.elems Ru:44:Ruthenium quiz.elems Rh:45:Rhodium quiz.elems Pd:46:Palladium quiz.elems Ag:47:Silver|Argentum quiz.elems Cd:48:Cadmium quiz.elems In:49:Indium quiz.elems Sn:50:Tin|Stannum quiz.elems Sb:51:Antimony|Stibium quiz.elems Te:52:Tellurium quiz.elems I:53:Iodine quiz.elems Xe:54:Xenon quiz.elems Cs:55:Cesium quiz.elems Ba:56:Barium quiz.elems La:57:Lanthanum quiz.elems Ce:58:Cerium quiz.elems Pr:59:Praseodymium quiz.elems Nd:60:Neodymium quiz.elems Pm:61:Promethium quiz.elems Sm:62:Samarium quiz.elems Eu:63:Europium quiz.elems Gd:64:Gadolinium quiz.elems Tb:65:Terbium quiz.elems Dy:66:Dysprosium quiz.elems Ho:67:Holmium quiz.elems Er:68:Erbium quiz.elems Tm:69:Thulium quiz.elems Yb:70:Ytterbium quiz.elems Lu:71:Lutetium quiz.elems Hf:72:Hafnium quiz.elems Ta:73:Tantalum quiz.elems W:74:Tungsten|Wolfram quiz.elems Re:75:Rhenium quiz.elems Os:76:Osmium quiz.elems Ir:77:Iridium quiz.elems Pt:78:Platinum quiz.elems Au:79:Gold|Aurum quiz.elems Hg:80:Mercury quiz.elems Tl:81:Thallium quiz.elems Pb:82:Lead|Plumbum quiz.elems Bi:83:Bismuth quiz.elems Po:84:Polonium quiz.elems At:85:Astatine quiz.elems Rn:86:Radon quiz.elems Fr:87:Francium quiz.elems Ra:88:Radium quiz.elems Ac:89:Actinium quiz.elems Th:90:Thorium quiz.elems Pa:91:Protactinium quiz.elems U:92:Uranium quiz.elems Np:93:Neptunium quiz.elems Pu:94:Plutonium quiz.elems Am:95:Americium quiz.elems Cm:96:Curium quiz.elems Bk:97:Berkelium quiz.elems Cf:98:Californium quiz.elems Es:99:Einsteinium quiz.elems Fm:100:Fermium quiz.elems Md:101:Mendelevium quiz.elems No:102:Nobelium quiz.elems Lw:103:Lawrencium quiz # quiz - present a quiz quiz # usage: awk -f quiz topicfile question-subj answer-subj quiz quiz BEGIN { quiz FS = ":" quiz if (ARGC != 4) quiz error("usage: awk -f quiz topicfile question answer") quiz if (getline NF || a > NF || q == a) quiz error("valid subjects are " $0) quiz while (getline 0) # load the quiz quiz qa[++nq] = $0 quiz ARGC = 2; ARGV[1] = "-" # now read standard input quiz srand() quiz do { quiz split(qa[int(rand()*nq + 1)], x) quiz printf("%s? ", x[q]) quiz while ((input = getline) > 0) quiz if ($0 ~ "^(" x[a] ")$") { quiz print "Right!" quiz break quiz } else if ($0 == "") { quiz print x[a] quiz break quiz } else quiz printf("wrong, try again: ") quiz } while (input > 0) quiz } quiz quiz function error(s) { printf("error: %s\n", s); exit } wordfreq # wordfreq - print number of occurrences of each word wordfreq # input: text wordfreq # output: number-word pairs sorted by number wordfreq wordfreq { gsub(/[.,:;!?(){}]/, "") # remove punctuation wordfreq for (i = 1; i <= NF; i++) wordfreq count[$i]++ wordfreq } wordfreq END { for (w in count) wordfreq print count[w], w | "sort -rn" wordfreq } fmt # fmt - format fmt # input: text fmt # output: text formatted into lines of <= 60 characters fmt fmt /./ { for (i = 1; i <= NF; i++) addword($i) } fmt /^$/ { printline(); print "" } fmt END { printline() } fmt fmt function addword(w) { fmt if (length(line) + length(w) > 60) fmt printline() fmt line = line " " w fmt } fmt fmt function printline() { fmt if (length(line) > 0) { fmt print substr(line, 2) # removes leading blank fmt line = "" fmt } fmt } fmt.just # fmt.just - formatter with right justification fmt.just fmt.just BEGIN { blanks = sprintf("%60s", " ") } fmt.just /./ { for (i = 1; i <= NF; i++) addword($i) } fmt.just /^$/ { printline("no"); print "" } fmt.just END { printline("no") } fmt.just fmt.just function addword(w) { fmt.just if (cnt + size + length(w) > 60) fmt.just printline("yes") fmt.just line[++cnt] = w fmt.just size += length(w) fmt.just } fmt.just fmt.just function printline(f, i, nb, nsp, holes) { fmt.just if (f == "no" || cnt == 1) { fmt.just for (i = 1; i <= cnt; i++) fmt.just printf("%s%s", line[i], i < cnt ? " " : "\n") fmt.just } else if (cnt > 1) { fmt.just dir = 1 - dir # alternate side for extra blanks fmt.just nb = 60 - size # number of blanks needed fmt.just holes = cnt - 1 # holes fmt.just for (i = 1; holes > 0; i++) { fmt.just nsp = int((nb-dir) / holes) + dir fmt.just printf("%s%s", line[i], substr(blanks, 1, nsp)) fmt.just nb -= nsp fmt.just holes-- fmt.just } fmt.just print line[cnt] fmt.just } fmt.just size = cnt = 0 fmt.just } xref.data .#Fig _quotes_ xref.data Figure _quotes_ gives two brief quotations from famous books. xref.data xref.data Figure _quotes_: xref.data xref.data .#Bib _alice_ xref.data "... `and what is the use of a book,' thought Alice, xref.data `without pictures or conversations?'" [_alice_] xref.data xref.data .#Bib _huck_ xref.data "... if I'd a knowed what a trouble it was to make a book xref.data I wouldn't a tackled it and ain't agoing to no more." [_huck_] xref.data xref.data xref.data [_alice_] Carroll, L., Alice's Adventures in Wonderland, xref.data Macmillan, 1865. xref.data [_huck_] Twain, M., Adventures of Huckleberry Finn, xref.data Webster & Co., 1885. xref # xref - create numeric values for symbolic names xref # input: text with definitions for symbolic names xref # output: awk program to replace symbolic names by numbers xref xref /^\.#/ { printf("{ gsub(/%s/, \"%d\") }\n", $2, ++count[$1]) } xref END { printf("!/^[.]#/\n") } xref.ans /^\.#/ { printf("{ gsub(/%s/, \"%d\") }\n", $2, ++count[$1]) xref.ans if (saw[$2]) xref.ans print NR ": redefinition of", $2, "from line", saw[$2] xref.ans saw[$2] = NR xref.ans } xref.ans END { printf("!/^[.]#/\n") } xref1.ans /^\.#/ { s[$2] = ++count[$1]; next } xref1.ans { for (i in s) xref1.ans gsub(i, s[i]) xref1.ans print xref1.ans } say.in.kwic All's well that ends well. say.in.kwic Nature abhors a vacuum. say.in.kwic Every man has a price. kwic awk ' kwic # kwic - generate kwic index kwic kwic { print $0 kwic for (i = length($0); i > 0; i--) # compute length only once kwic if (substr($0,i,1) == " ") kwic # prefix space suffix ==> suffix tab prefix kwic print substr($0,i+1) "\t" substr($0,1,i-1) kwic } ' | kwic sort -f | kwic awk ' kwic BEGIN { FS = "\t"; WID = 30 } kwic { printf("%" WID "s %s\n", substr($2,length($2)-WID+1), kwic substr($1,1,WID)) kwic } ' kwic.ans awk ' kwic.ans # kwic - generate kwic index kwic.ans kwic.ans { print $0 kwic.ans for (i = length($0); i > 0; i--) # compute length only once kwic.ans if (substr($0,i,1) == " ") kwic.ans # prefix space suffix ==> suffix tab prefix kwic.ans print substr($0,i+1) "\t" substr($0,1,i-1) kwic.ans } ' | kwic.ans awk '$1 !~ /^(a|an|and|by|for|if|in|is|of|on|the|to)$/' | kwic.ans sort -f | kwic.ans awk ' kwic.ans BEGIN { FS = "\t"; WID = 30 } kwic.ans { printf "%" WID "s %s\n", substr($2,length($2)-WID+1), kwic.ans substr($1,1,WID) kwic.ans } ' ix.raw [FS] variable 35 ix.raw [FS] variable 36 ix.raw arithmetic operators 36 ix.raw coercion rules 44 ix.raw string comparison 44 ix.raw numeric comparison 44 ix.raw arithmetic operators 44 ix.raw coercion~to number 45 ix.raw coercion~to string 45 ix.raw [if]-[else] statement 47 ix.raw control-flow statements 48 ix.raw [FS] variable 52 ix.collapse # ix.collapse - combine number lists for identical terms ix.collapse # input: string tab num \n string tab num ... ix.collapse # output: string tab num num ... ix.collapse ix.collapse BEGIN { FS = OFS = "\t" } ix.collapse $1 != prev { ix.collapse if (NR > 1) ix.collapse printf("\n") ix.collapse prev = $1 ix.collapse printf("%s\t%s", $1, $2) ix.collapse next ix.collapse } ix.collapse { printf(" %s", $2) } ix.collapse ix.collapse END { if (NR > 1) printf("\n") } ix.rotate # ix.rotate - generate rotations of index terms ix.rotate # input: string tab num num ... ix.rotate # output: rotations of string tab num num ... ix.rotate ix.rotate BEGIN { FS = OFS = "\t" } ix.rotate { print $1, $2 # unrotated form ix.rotate for (i = 1; (j = index(substr($1, i+1), " ")) > 0; ) { ix.rotate i += j # find each blank, rotate around it ix.rotate printf("%s, %s\t%s\n", ix.rotate substr($1, i+1), substr($1, 1, i-1), $2) ix.rotate } ix.rotate } ix.genkey # ix.genkey - generate sort key to force ordering ix.genkey # input: string tab num num ... ix.genkey # output: sort key tab string tab num num ... ix.genkey ix.genkey BEGIN { FS = OFS = "\t" } ix.genkey ix.genkey { gsub(/~/, " ", $1) # tildes now become blanks ix.genkey key = $1 ix.genkey # remove troff size and font change commands from key ix.genkey gsub(/\\f.|\\f\(..|\\s[-+][0-9]/, "", key) ix.genkey # keep blanks, letters, digits only ix.genkey gsub(/[^a-zA-Z0-9 ]+/, "", key) ix.genkey if (key ~ /^[^a-zA-Z]/) # force nonalpha to sort first ix.genkey key = " " key # by prefixing a blank ix.genkey print key, $1, $2 ix.genkey } ix.sort1 # ix.sort1 - sort by index term, then by page number ix.sort1 # input/output: lines of the form string tab number ix.sort1 # sort by string, then by number; discard duplicates ix.sort1 ix.sort1 sort -t' ' +0 -1 +1n -2 -u ix.sort2 # ix.sort2 - sort by sort key ix.sort2 # input/output: sort-key tab string tab num num ... ix.sort2 ix.sort2 sort -f -d ix.format # ix.format - remove key, restore size and font commands ix.format # input: sort key tab string tab num num ... ix.format # output: troff format, ready to print ix.format ix.format BEGIN { FS = "\t" } ix.format ix.format { gsub(/ /, ", ", $3) # commas between page numbers ix.format gsub(/\[/, "\\f(CW", $2) # set constant-width font ix.format gsub(/\]/, "\\fP", $2) # restore previous font ix.format print ".XX" # user-definable command ix.format printf("%s %s\n", $2, $3) # actual index entry ix.format } indall sh ix.sort1 | indall awk -f ix.collapse | indall awk -f ix.rotate | indall awk -f ix.genkey | indall sh ix.sort2 | indall awk -f ix.format .