[RndTbl] shell quoting inside $( )?

Adam Thompson athompso at athompso.net
Sun Feb 26 21:00:56 CST 2023


Found my answer, sort of.  Either use mkfiko and tee, or use bash/zsh/ksh88 process substitution a la "cmd >(subcmd1) >(subcmd2)", 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.

> T=$(openssl x509 -noout -text -in "$1")
> EXPD=$(date -d"$(echo "$T" | sed -n 's/^.*Not After : //p')" +%Y%b%d)
> SUBJ=$(echo "$T" | sed -n 's/^.*Subject: .*CN = //p')

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>

Talk about unreadable, though!

This does several things, as I understand it:
1. duplicate /dev/fd/1 (stdout) to, usually, /dev/fd/4 but it doesn't really matter which FD#
2. spawns the first subshell, and passes /dev/fd/1 as that subshell's stdin, and the subshell's stdout as the parent process's stdout
3. spawns the second subshell, and passes the dup'd FD (/dev/fd/4 or whatever it is) as that subshell's stdin, and the subshell's stdout as the parent process's stdout
4. collects all the output

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...

-Adam


-----Original Message-----
From: Trevor Cordes <trevor at tecnopolis.ca> 
Sent: Sunday, February 26, 2023 8:23 PM
To: Adam Thompson <athompso at athompso.net>
Cc: Continuation of Round Table discussion <roundtable at muug.ca>
Subject: Re: [RndTbl] shell quoting inside $( )?

I can't see any way to "bifurcate output" in bash without using tee.
I'm pretty sure zsh (and probably fish) can do it, but not sure of
the syntax there either:

$ eval $((openssl x509 -noout -text -in /etc/pki/tls/certs/tecnopolis.ca.crt | tee >(echo -n EXPD="'"`date -d"$(sed -n 's/^.*Not After : //p')" +%Y%b%d`"'" )  >(echo SUBJ="'"`sed -n 's/^.*Subject: .*CN = //p'`"'" ) 1>&2 ) 2>/dev/null)

$ echo $SUBJ tecnopolis.ca
$ echo $EXPD 2024Feb22

If you can figure out a way to get the vars out of the subshell and
into 2 different vars without using the eval $() then you're probably
better off.  Even though I protect the tainted inputs with '', someone
could possibly plant a ' in the SUBJ and thus this is a sec hole.

Of course you could eliminate the eval and assign to a var and then
run a 2nd command to split them into SUBJ and EXPD, but I was going
for a oneliner.  (Get rid of the "'" adders then.)

I'm going to toy with the idea of using {} subshells which might
allow elimination of the eval.

Of course this would be much cleaner in a perl oneliner... and if
you're already bringing in sed, how much worse is perl?



More information about the Roundtable mailing list