cloverleaf-larry/lib/len2nl.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

39 lines
1.2 KiB
Bash
Executable File

#!/usr/bin/env bash
# len2nl.sh — convert length-prefixed and/or MLLP-framed HL7 to newline-readable.
#
# Handles both common framing patterns:
# 1. Length-prefix: `<digits>MSH|...` → strip leading digits before MSH
# 2. MLLP: `\x0b...\x1c\x0d` → strip VT and FS+CR end-block
# 3. Segment CRs: `<seg>\r<seg>\r...` → replace \r with \n
#
# After conversion, each segment is on its own line (LF), making the message
# greppable / pageable.
#
# Usage:
# len2nl.sh [FILE] # file or stdin
# cat raw.hl7 | len2nl.sh
# tcpdump ... | len2nl.sh
#
# This is a strict superset of the v1 `len2nl` behavior.
set -o pipefail
usage() { sed -n '2,18p' "$0"; exit 0; }
case "${1:-}" in -h|--help) usage ;; esac
INPUT="${1:-}"
if [ -n "$INPUT" ] && [ ! -f "$INPUT" ]; then
echo "len2nl: no such file: $INPUT" >&2; exit 2
fi
if [ -n "$INPUT" ]; then
CMD=(cat "$INPUT")
else
CMD=(cat)
fi
"${CMD[@]}" \
| tr -d '\013' `# strip MLLP VT (0x0B = start-block)` \
| sed 's/\x1c\x0d//g' `# strip MLLP FS+CR (0x1C 0x0D = end-block)` \
| sed -E 's/[0-9]+MSH\|/MSH|/g' `# strip numeric length-prefix before MSH` \
| tr '\r' '\n' `# CR-separated segments → LF`