add a -u option: flush output after printing each value (unbuffered) - json2tsv - JSON to TSV converter (HTM) git clone git://git.codemadness.org/json2tsv (DIR) Log (DIR) Files (DIR) Refs (DIR) README (DIR) LICENSE --- (DIR) commit 658cf342ce46348def6651d715b404a40baadb4f (DIR) parent 994b5ebefdc81372822b42917e254ee1b0728db0 (HTM) Author: Hiltjo Posthuma <hiltjo@codemadness.org> Date: Sun, 23 Apr 2023 12:39:38 +0200 add a -u option: flush output after printing each value (unbuffered) This works similar to the sed -u option. Sometimes it can be useful to force flushing the data directly. For example for streaming JSON data. Diffstat: M jaq | 13 +++++++------ M jaq.1 | 5 ++++- M json2tsv.1 | 5 ++++- M json2tsv.c | 8 ++++++-- 4 files changed, 21 insertions(+), 10 deletions(-) --- (DIR) diff --git a/jaq b/jaq @@ -1,12 +1,13 @@ #!/bin/sh -nflag="" -if [ "$1" = "-n" ]; then - nflag="-n" +flags="" +while [ $# -gt 0 ]; do + [ "$1" = "-n" -o "$1" = "-u" ] || break + flags="${flags} $1" shift -fi +done if [ $# -le 0 ]; then - echo "usage: jaq [-n] <awk expressions...>" >&2 + echo "usage: jaq [-n] [-u] <awk expressions...>" >&2 exit 1 fi expr="$*" @@ -14,7 +15,7 @@ expr="$*" # POSIX way to simulate -o pipefail if JSON data is invalid. statusfile="$(mktemp)" || exit 1 trap -- "rm -f \"${statusfile}\"" "EXIT" -{ json2tsv ${nflag} -r -F '\x1f' -R '\x1e'; echo $? >"${statusfile}"; } | \ +{ json2tsv ${flags} -r -F '\x1f' -R '\x1e'; echo $? >"${statusfile}"; } | \ LC_ALL=C awk "BEGIN { FS = \"\x1f\"; RS = \"\x1e\" }${expr}" statuscode="$(cat "${statusfile}" 2>/dev/null)$?" [ "${statuscode}" = "00" ] (DIR) diff --git a/jaq.1 b/jaq.1 @@ -1,4 +1,4 @@ -.Dd September 1, 2022 +.Dd April 17, 2023 .Dt JAQ 1 .Os .Sh NAME @@ -7,6 +7,7 @@ .Sh SYNOPSIS .Nm .Op Fl n +.Op Fl u .Ar awk expressions... .Sh DESCRIPTION .Nm @@ -26,6 +27,8 @@ The options are as follows: .Bl -tag -width Ds .It Fl n Show the indices for array types (by default off). +.It Fl u +Unbuffered: flush output after printing each value (by default off). .El .Pp The options (DIR) diff --git a/json2tsv.1 b/json2tsv.1 @@ -1,4 +1,4 @@ -.Dd September 1, 2022 +.Dd April 17, 2023 .Dt JSON2TSV 1 .Os .Sh NAME @@ -8,6 +8,7 @@ .Nm .Op Fl n .Op Fl r +.Op Fl u .Op Fl F Ar fs .Op Fl R Ar rs .Sh DESCRIPTION @@ -21,6 +22,8 @@ The options are as follows: Show the indices for array types (by default off). .It Fl r Show all control-characters (by default off). +.It Fl u +Unbuffered: flush output after printing each value (by default off). .It Fl F Ar fs Use .Ar fs (DIR) diff --git a/json2tsv.c b/json2tsv.c @@ -19,6 +19,7 @@ static int nflag = 0; /* -n flag: show indices count for arrays */ static int rflag = 0; /* -r flag: show all control-characters */ +static int uflag = 0; /* -u flag: flush output after printing each value */ static int fs = '\t', rs = '\n'; static void (*printvalue)(const char *, size_t); @@ -120,7 +121,7 @@ processnode(struct json_node *nodes, size_t depth, const char *value, size_t val printvalue(value, valuelen); putchar(rs); - if (ferror(stdout)) { + if ((uflag && fflush(stdout)) || ferror(stdout)) { fprintf(stderr, "write error: <stdout>\n"); exit(2); } @@ -178,7 +179,7 @@ readchar(const char *s) void usage(const char *argv0) { - fprintf(stderr, "usage: %s [-n] [-r] [-F fs] [-R rs]\n", argv0); + fprintf(stderr, "usage: %s [-n] [-r] [-u] [-F fs] [-R rs]\n", argv0); exit(3); } @@ -202,6 +203,9 @@ main(int argc, char *argv[]) case 'r': rflag = 1; break; + case 'u': + uflag = 1; + break; case 'F': if (i + 1 >= argc) usage(argv[0]);