cloverleaf-larry/lib/csv-to-table.sh
Bryan Johnson 3eb88f86c8 v0.4.1: each / each-site / len2nl / csv-to-table / table-to-csv
Five small Unix-style loop & format helpers, fully offline:

lib/each.sh
  - replaces v1 `each`
  - run a CMD per item: args, stdin lines, or {}-placeholder substitution
  - example: tbn adt | awk '{print $2}' | each.sh 'route_test {}'

lib/each-site.sh
  - replaces v1 each_site / each_site_hdr / each_site_tcl patterns
  - iterates every site under $HCIROOT with HCISITE/HCISITEDIR auto-exported
  - --filter REGEX limits which sites; --hdr prints a header before each

lib/len2nl.sh
  - replaces v1 `len2nl`
  - strict superset: handles length-prefixed (digits before MSH),
    MLLP (\x0b...\x1c\x0d), and segment CRs (→ LF)
  - works as stdin filter or with file arg

lib/csv-to-table.sh
  - 2-column CSV → Cloverleaf .tbl format
  - emits proper prologue (who, date, bidir, type, version)
  - --has-header --default VALUE --bidir 0|1 --in-delim CHAR --user NAME --out PATH

lib/table-to-csv.sh
  - reverse: .tbl → CSV
  - --with-header --delim CHAR --include-meta
  - confirmed clean round-trip: CSV → table → CSV byte-identical for the data rows

All 5 are pipeable, have --help, zero external deps beyond bash+awk+sed.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-26 11:05:19 -07:00

103 lines
2.2 KiB
Bash
Executable File

#!/usr/bin/env bash
# csv-to-table.sh — convert a 2-column CSV into Cloverleaf .tbl format.
#
# Input CSV (with or without header):
# input,output
# 12345,M
# 12346,F
# ...
#
# Output Cloverleaf .tbl:
# # Generated by csv-to-table.sh
# prologue
# who: <user>
# date: <iso8601>
# outname: output
# inname: input
# bidir: 0
# type: tbl
# version: 7.0
# end_prologue
# dflt=__non-existent__
# #
# 12345
# M
# encoded=0,0
# #
# 12346
# F
# ...
#
# Usage:
# csv-to-table.sh [FILE] [--default VALUE] [--bidir 0|1] [--has-header]
# [--in-delim CHAR] # default ','
# [--user NAME] # default $USER
# [--out PATH] # default stdout
set -o pipefail
usage() { sed -n '2,30p' "$0"; exit 0; }
INPUT=""
DEFAULT="__non-existent__"
BIDIR=0
HAS_HEADER=0
DELIM=','
USER_NAME="${USER:-larry}"
OUT_FILE=""
while [ $# -gt 0 ]; do
case "$1" in
--default) shift; DEFAULT="$1" ;;
--bidir) shift; BIDIR="$1" ;;
--has-header) HAS_HEADER=1 ;;
--in-delim) shift; DELIM="$1" ;;
--user) shift; USER_NAME="$1" ;;
--out) shift; OUT_FILE="$1" ;;
-h|--help) usage ;;
-*) echo "csv-to-table: unknown flag: $1" >&2; exit 2 ;;
*) INPUT="$1" ;;
esac
shift
done
[ -z "$INPUT" ] || [ -f "$INPUT" ] || { echo "csv-to-table: no such file: $INPUT" >&2; exit 2; }
emit() {
cat <<EOF
# Generated by larry-anywhere csv-to-table.sh
prologue
who: ${USER_NAME}
date: $(date -Iseconds 2>/dev/null || date)
outname: output
inname: input
bidir: ${BIDIR}
type: tbl
version: 7.0
end_prologue
#
dflt=${DEFAULT}
#
EOF
awk -F"$DELIM" -v has_header="$HAS_HEADER" '
NR == 1 && has_header == 1 { next }
NF >= 2 {
# Trim whitespace
gsub(/^[ \t"]+|[ \t"]+$/, "", $1)
gsub(/^[ \t"]+|[ \t"]+$/, "", $2)
if ($1 == "") next
print $1
print $2
print "encoded=0,0"
print "#"
}
' "${INPUT:-/dev/stdin}"
}
if [ -n "$OUT_FILE" ]; then
mkdir -p "$(dirname "$OUT_FILE")" 2>/dev/null
emit > "$OUT_FILE"
printf 'csv-to-table: wrote %s\n' "$OUT_FILE" >&2
else
emit
fi