# testall.cmds -- one shell command per line; `testall` runs them in a scratch copy of demo/. # ## line is printed as a heading/explanation # line is a silent comment # Save a known-good run: testall > testall.old later: testall | diff testall.old - # Tables used here: inventory journal expense carexpense parent female male owners # chart ledger parttable cash X83 colors orders ed.t maillist form name ## ## ===== Selecting and arranging rows and columns ===== ## row (select): keep the rows that match a condition. Column names work like awk variables. row 'Cost > 5' < inventory rdb select 'Description ~ /gloves/' < inventory ## column (project): pick columns in any order; a name that does not exist becomes a new empty column column Description Cost < inventory project Item Notes < owners ## sorttable: -n numeric, -r reverse, -f fold case sorttable -nr Cost < inventory ## compute: calculate columns from other columns (the new column must exist, so make it with addcol) addcol Total < inventory | compute 'Total = Amount * Cost' | column Item Total compute 'Value = sprintf("%5.2f", Cost * Amount)' < inventory ## addcol / rename addcol Supplier < owners rename Owner Person < owners ## number / Number: number the rows (number: rows only, Number: rows and the head) number < owners Number < owners ## record: print one record (the 3rd row) record 3 < inventory ## rmblank: drop empty rows; headon / headoff: add or strip the head column Item Cost < inventory | rmblank headoff < colors headoff < colors | headon Hue printf 'a\tb\n1\t2\n' | insertdash ## splittable: cut a table horizontally into pieces of n rows (writes colorsaa, colorsab ...) splittable -3 colors ; ls colors* ; cat colorsab ## ===== Combining tables ===== ## jointable: join on the first column; -a keeps unmatched rows, -j names the key columns jointable inventory owners jointable -a inventory owners jointable -j1 Parent -j2 Name parent female ## union / intersect / difference union expense carexpense intersect female male difference female male ## paste.rdb: put tables side by side paste.rdb female male ## ===== Statistics: one result row per column ===== total Amount Value < inventory mean Cost < inventory maximum Cost < inventory minimum Cost < inventory width < inventory precision Cost < inventory datatype -l < inventory widest < inventory subtotal Date Debit Credit < journal dbdict < inventory schema inventory owners tableorlist inventory maillist ## ===== Checking and displaying ===== check.rdb < inventory printf 'a\tb\n-\t-\n1\t2\t3\n4\n' | check.rdb display < owners see < owners validate 'Cost > 40 { print "expensive:", Description }' < badinventory column Colors < orders | domain colors domain colors black x ## fd: does Description depend on Item? (prints true/false) fd Item Description < inventory fd Description Cost < inventory ## ===== Text tools (arguments or standard input) ===== justify < inventory justify -r Description < inventory justify -c Cost < inventory trim < inventory compresss < inventory pad -4 < owners printf 'hello world\n' | cap uppercase hello world lowercase HELLO WORLD printf 'one two\n' | uppercase substitute gloves mittens colors ; cat colors trimblank ' padded ' padstring 8 abc padstring -8 abc length 'how long?' filesize inventory ascii aA1 ascii ' ' chr 72 105 word < ed.t cap < ed.t blank < maillist printf 'a\n' | prompt 'prompt text' not false && echo 'false failed, so not succeeded' path ls > /dev/null && echo 'ls found on the path' ## tabletom4 / tabletosed make translation files from ed.t; translate applies them tabletom4 < ed.t tabletosed < ed.t tabletom4 < ed.t > ed ; echo 'I love you.' | translate ed ## uniondict builds the ed define-file out of ed.low and ed.allcap printf 'English\tDeutsch\n-------\t-------\nlove\tliebe\n' > ed.low ; printf 'English\tDeutsch\n-------\t-------\nLOVE\tLIEBE\n' > ed.allcap ; uniondict ed ## ===== Conversions ===== tabletolist < owners tabletolist -l < owners tabletolist < owners | listtotable listtotable < maillist listtosh < maillist tabletofix Item=4 Owner=6r < owners tabletofix Item=4 Owner=6r < owners | fixtotable Item=1,4 Owner=5,6 tabletostruct tag owners < owners tabletotbl < owners tabletofact parent tabletorule ruletable ## ===== Dates ===== ## julian: dates to day numbers (arithmetic); gregorian: back again (-e European, -u US, -c day count) julian Date < journal julian Date < journal | gregorian Date julian Date < journal | gregorian -e Date ## computedate: a date plus n days computedate 890331 45 computedate 891231 1 test $(todaysdate | wc -c) -eq 7 && echo 'todaysdate prints YYMMDD' ## ===== Names that sound alike ===== soundex < name ## like: names that sound like Mann (needs the soundex table name.x, sorted by Soundex) soundex < name > name.x ; like Mann name hashkey 11 ABCD hashkey 29 abcdefg ## ===== Fast access: index, search, seek ===== ## search without an index scans the table (-ms); keys come from stdin echo scales | search inventory Description ## -h leaves out the head line of the answer printf 'Description\n-----------\nscales\n' | search -h inventory Description ## build indexes in each method: b binary, r record, i inverted, h hash index -mr inventory ; ls inventory.r ; echo 3 | search -mr inventory index -mi inventory Description ; ls inventory.i ; echo cl | search -mi -x inventory Description index -mh inventory Item ; ls inventory.h ; echo 5 | search -mh inventory Item ## seek: where does the row start and end? (byte offsets) echo 5 | seek inventory Item echo 5 | seek -mh inventory Item ## searchtree: is Sally an ancestor of Jane? (needs a table of Parent, Child) searchtree parent Sally Jane Parent Child ## vindex: look-up tables for ve vindex owners Item : Owner ; vindex owners tableorlist owners maillist ## ===== Changing tables: append, replace, delete, enter ===== ## append adds a row and updates the indexes ## -h: the new row has no head line printf '8\t1\t1.00\t1.00\tnew thing\n' | append -h -mh inventory Item ; echo 8 | search -mh inventory Item ## replace overwrites bytes from..to; take the offsets from seek set -- $(echo 3 | seek inventory Item) ; printf '3\t6\t8.00\t48.00\tclamps\n' | replace inventory $1 $2 ; echo 3 | search inventory Item ## delete blanks the row and fixes the index echo 4 | delete -mh inventory Item ; echo 4 | search -mh inventory Item ; echo 5 | search -mh inventory Item ## enter reads rows field by field from the terminal; -1 means one row printf '9\n2\n3\n4\nnewer thing\n' | enter -1 inventory > /dev/null tail -1 inventory ## lock / unlock: the second process may not lock the same bytes lock inventory 111 10 20 0 0 ; echo "first lock status $?" lock inventory 222 15 25 0 0 ; echo "second lock status $?" unlock inventory 111 10 20 0 0 ; echo "unlock status $?" lock inventory 222 15 25 0 0 ; echo "second lock now status $?" ; unlock inventory 222 15 25 0 0 ## vilock edits a table under a lock; update.rdb edits records interactively echo | vilock inventory ; echo "vilock status $?" ## update.rdb with a key on stdin and no changes (an empty line ends the dialog) printf '3\n\n' | update.rdb inventory Item | head -8 ## ve is a line editor in this version printf 'q\n' | ve inventory | head -3 ## ===== Reports and forms ===== ## report fills a form with the fields of each list record () cat form report form < maillist ## label prints mailing labels, letter prints form letters label < maillist letter form < maillist | head -5 ## screen turns a form into a shell script that asks for the fields. Use a form with labels ## and every column once (entry); the report template `form` would give a blank, doubled screen. ## Run the script with: CLEAR=$(clear.rdb) sh script > table 2>&1 (the table goes to stderr) cat entry screen < entry ## mask draws the form itself (fields, buttons, frame) and writes the row as a table on stdout. ## It needs a terminal, so here only the picture of the form and its fields (-s) is shown. ## Try it: mask -b < maskform mask < maskform | append -h t cat maskform mask -s -b < maskform ## reportwriter: a sample report with page headings (the date is cut out) reportwriter -3 Prices < inventory | grep -v 'Report Date' ## tabletom4 / tabletosed / tabletostruct were shown above ## ===== Help and the terminal ===== rdb --version howmany whatis row whatwill total helpme commands | head -5 man -g column | head -12 termput cl | cat -v termput cm | cat -v tset vt100 | head -3 cursor 3 8 | cat -v clear.rdb | cat -v rmcore ; echo "rmcore status $?" mkdir t1 ; cp owners t1 ; cpdir.rdb t1 t2 ; ls t2 menu < /dev/null | head -3 timesearch > /dev/null ; echo "timesearch status $?" testsearch | tail -3 act ## ===== /act: a small accounting system ===== ## (the commands work on tables in the current directory; NEXTDATE fixes the date they use) act ## cashflow: compute the Balance column of a cash table cashflow < cash ## tax: look up the tax for an income in a tax table tax 20000 < X83 ## explode: parts list -> all subparts with counts (part, amount) explode 10001 2 parttable ## chartdup: look for duplicate account numbers and short names in chart printf 'Account\tShort\n-------\t-----\n1\ta\n1\tb\n2\ta\n' > chart ; chartdup ## foot: subtotals of Debit and Credit per account in the ledger foot ## adjust, balance, close: need a trial balance and an adjusting journal printf 'Account\tDebit\tCredit\tFormat\tTaxline\tShort\tName\n-------\t-----\t------\t------\t-------\t-----\t----\n1010\t11178\t\tB-A\t4L01\tcash\tCash\n3010\t\t13500\tI-I\t101a\tsales\tSales\n' > trialbalance printf 'Account\tDebit\tCredit\tFormat\tTaxline\tName\n-------\t-----\t------\t------\t-------\t----\n1010\t100\t\tB-A\t4L01\tCash\n' > journaladjust adjust ; cat adjustedtrial balance ; sed 2d balancesheet NEXTDATE=870101 close ; cat journalnext ## fillform: sum the adjusted trial balance per tax line into a tax form printf 'Taxline\tDescription\n-------\t-----------\n4L01\tCash on hand\n101a\tGross sales\n' > taxform.f1 fillform f1 ; cat f1 ## calculate: compute columns of a form; f1.calc has one 'Column = expression' per line echo 'Amount = Amount * 2' > f1.calc ; calculate f1 ; cat f1 ## getjournal / consolidate: collect subsidiary journals into the general journal printf 'Date\tAmount\tAccount\tRef\tDescription\n----\t------\t-------\t---\t-----------\n870101\t100\t4010\ts1\tshop sale\n' > journalsales NEXTDATE=870131 getjournal journalsales printf 'Date\tAmount\tAccount\tRef\tDescription\n----\t------\t-------\t---\t-----------\n870102\t40\t5010\tp1\tpaper\n' > journalexpense rm journal ; consolidate 870131 ; cat journal ## payroll: calcpay sorts journalpay into ledgerpay, w2 totals per employee printf 'Number\tGross\tFederal\tState\tNet\n------\t-----\t-------\t-----\t---\n2\t1000\t100\t50\t850\n1\t900\t90\t40\t770\n2\t1000\t100\t50\t850\n' > journalpay calcpay ; cat ledgerpay w2 ## ===== /act: sales and stock ===== printf 'Code\tName\tPrice\n----\t----\t-----\n10010\twidget\t2.50\n10020\tgadget\t10\n' > product printf 'Number\tCompany\tLast\n------\t-------\t----\n7\tAcme\tRoe\n' > customer ## sale: enter a sale order (customer, then code and quantity per item, then y to confirm) printf '7\n10010\n4\n10020\n1\n\ny\n\n' | NEXTDATE=870105 sale cat salesorder ## invoice / cstate: print an invoice or customer statement for what was sold printf '1\n\n' | invoice printf '7\n\n' | cstate ## bom: parts needed for everything sold (needs the table part with Code, Subpart, Count) printf 'Code\tSubpart\tCount\n----\t-------\t-----\n10010\ts1\t3\n10020\ts1\t1\n10020\ts2\t2\n' > part bom ; cat bom ## update.inv: change the stock of one item, with record locking (INV names the table) cp inventory inv ; printf '7\n9\n\n' | INV=inv update.inv | tail -n +2 grep '^7' inv