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>
71 lines
2.0 KiB
Bash
Executable File
71 lines
2.0 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# table-to-csv.sh — convert a Cloverleaf .tbl file to CSV.
|
|
#
|
|
# Reverses csv-to-table.sh. Skips the prologue, dflt= line, encoded= meta,
|
|
# comment lines, and #-separator lines; emits "input,output" rows.
|
|
#
|
|
# Usage:
|
|
# table-to-csv.sh [FILE] # file or stdin
|
|
# table-to-csv.sh --with-header [FILE] # emit "input,output" header
|
|
# table-to-csv.sh --delim ';' [FILE] # output delimiter (default ',')
|
|
# table-to-csv.sh --include-meta [FILE] # also emit prologue/default rows
|
|
set -o pipefail
|
|
|
|
usage() { sed -n '2,12p' "$0"; exit 0; }
|
|
|
|
INPUT=""
|
|
WITH_HEADER=0
|
|
DELIM=','
|
|
INCLUDE_META=0
|
|
|
|
while [ $# -gt 0 ]; do
|
|
case "$1" in
|
|
--with-header) WITH_HEADER=1 ;;
|
|
--delim) shift; DELIM="$1" ;;
|
|
--include-meta) INCLUDE_META=1 ;;
|
|
-h|--help) usage ;;
|
|
-*) echo "table-to-csv: unknown flag: $1" >&2; exit 2 ;;
|
|
*) INPUT="$1" ;;
|
|
esac
|
|
shift
|
|
done
|
|
|
|
[ -z "$INPUT" ] || [ -f "$INPUT" ] || { echo "table-to-csv: no such file: $INPUT" >&2; exit 2; }
|
|
|
|
[ "$WITH_HEADER" = "1" ] && printf 'input%soutput\n' "$DELIM"
|
|
|
|
awk -v D="$DELIM" -v META="$INCLUDE_META" '
|
|
function csv_escape(s, needs_q) {
|
|
needs_q = (index(s, D) > 0 || index(s, "\"") > 0 || index(s, "\n") > 0)
|
|
gsub(/"/, "\"\"", s)
|
|
if (needs_q) return "\"" s "\""
|
|
return s
|
|
}
|
|
/^[[:space:]]*$/ { next }
|
|
/^[[:space:]]*#/ { next }
|
|
/^prologue$/ { in_prologue=1; next }
|
|
/^end_prologue$/ { in_prologue=0; next }
|
|
in_prologue { next }
|
|
/^dflt=/ {
|
|
if (META == "1") {
|
|
val = $0; sub(/^dflt=/, "", val)
|
|
print "__dflt__" D csv_escape(val)
|
|
}
|
|
next
|
|
}
|
|
/^encoded=/ { next }
|
|
{
|
|
line = $0
|
|
gsub(/^[[:space:]]+|[[:space:]]+$/, "", line)
|
|
if (line == "") next
|
|
if (waiting_for_output) {
|
|
print csv_escape(pending_input) D csv_escape(line)
|
|
pending_input = ""
|
|
waiting_for_output = 0
|
|
} else {
|
|
pending_input = line
|
|
waiting_for_output = 1
|
|
}
|
|
}
|
|
' "${INPUT:-/dev/stdin}"
|