On 2023-02-27 Adam Thompson wrote:
Found my answer, sort of. Either use mkfiko and tee, or use bash/zsh/ksh88 process substitution a la "cmd >(subcmd1) >(subcmd2)",
That's what I said half an hour ago! Doh
I managed to improve mine to eliminate the eval:
$ read SUBJ EXPD <<<$(echo $((openssl x509 -noout -text -in /etc/pki/tls/certs/tecnopolis.ca.crt |tee >(date -d"$(sed -n 's/^.*Not After : //p')" +%Y%b%d) >(sed -n 's/^.*Subject: .*CN = //p') 1>&2 ) 2>/dev/null))
$ echo "subj $SUBJ expd $EXPD" subj tecnopolis.ca expd 2024Feb22
but I don't see any good way of getting the output from subcmd1/2 into variables as they run in subshells. It would be do-able by piping the whole thing into a "while read X" loop, but that's arguably getting into "the cure is worse than the disease" territory.
Yes, the subshell/command problem is the difficult factor here. My updated example above also uses read, but without a loop. You need the echo and multi-subshells to get the 2 outputs onto 1 line.
Here's the funny part: the >() constructs start async ps's and you don't know whose output will come first! Yet no matter what I did the SUBJ always comes out first. I even put sleeps in the >() constructs to try to influence who outputs first, but it didn't matter! I wonder why the output order is the way it is (backwards) and always constant...
Untested as yet, but should work:
( openssl x509 -noout -text -in "$1" >(sed -n 's/^.*Not After : /A /p' | xargs date +%Y%b%d -d) >(sed -n 's/^.*Subject: .*CN = /B /p') ) | while read X; do case $X in A) EXPD="$X" ;; B) SUBJ="$X" ;; esac ;
<do something with EXPD and SUBJ>
Pretty sure you are *forced* to use tee or something like it. You can't just use >() with openssl. >() replaces itself with /dev/fd/X and sets up an async to read from it, which means nothing to openssl. You need tee to do the writing to that fd/X. Ran into that grief when I was working on it.
Nice: you are getting around the order issue with A / B, which is smart, but then kind of forces you into the loop. Still one line though. And the loop is no more evil than my read <<< echo hack.
If there were an easy way to "promote" shell variables up out of their subshell namespaces without needing `` or $() or read, subshells would be a heck of a lot more useful...
I was trying really hard to use my own fd's like 3 & 4 (not the ones used by >()) to get the output out of each >() construct and be able to differentiate them. But it wouldn't work... maybe because the >() is async, and I need to write to each fd in the construct and then read them out of the construct. Dunno. Use of fds 3 & 4 hurts my brain. Ideally the EXPD >() could write out to fd3 and SUBJ to fd4 and an outer shell could then read them. Or maybe that's impossible.