<p>The certs in kubernetes are base64 encoded and on the disk are plain certificate. We might have certs embedded in a yaml file. I was wondering if we can quickly verify the certs using either md5sum or viewing the cert contents as follows:</p>
<p>The first function tries to use pipes in variables and combines into a final form for the commandline, the second processes the intermediate results and uses the intermediate results in the final command.
The first function doesn't work because of extra quotes. The second function doesn't work because the '\n' in the content is lost somehow.</p>
<p>But the variable does not have the newline so the openssl doesnt read it well from the stdin.</p>
<p>Any suggestions on how to fix these functions?</p>
<pre class="lang-bash prettyprint-override"><code>function md5cert()
{
    md5cert_usage() { echo &quot;md5cert: [-f &lt;file&gt; |-c &lt;cmd&gt;] -p &lt;pat&gt;&quot; 1&gt;&amp;2; exit; }

    local OPTIND o a
    pflag=0
    while getopts &quot;:a:&quot; o; do
        case &quot;${o}&quot; in
            f)
                f=&quot;${OPTARG}&quot;
                cmd=&quot;cat $f&quot;
                decode=&quot; base64 -d | &quot;
                ;;
            c)
                cmd=&quot;${OPTARG}&quot;
                decode=&quot; base64 -d | &quot;
                ;;
            o)
                o=&quot;${OPTARG}&quot;
                cmd=&quot;cat ${f}&quot;
                decode=&quot; &quot;
                ;;
            p)
                p=&quot;${OPTARG}&quot;
                pflag=1
                ;;
            *)
                md5cert_usage

                ;;
        esac
    done
    shift $((OPTIND-1))
    if [ $pflag -eq  1 ]; then
       greppat=&quot;grep $p | awk '{print $2}' | &quot;
    fi

    $cmd | $greppat $decode md5sum
}

function readcert()
{
    readcert_usage() { echo &quot;readcert: [-f &lt;file&gt; |-c &lt;cmd&gt;] -p &lt;pat&gt;&quot; 1&gt;&amp;2; exit; }

    local OPTIND o a
    pflag=0
    while getopts &quot;:f:c:o:p:&quot; o; do
        case &quot;${o}&quot; in
            f)
                f=&quot;${OPTARG}&quot;
                cmd=&quot;cat $f&quot;
                decode=&quot; base64 -d | &quot;
                ;;
            c)
                cmd=&quot;${OPTARG}&quot;
                decode=&quot; base64 -d | &quot;
                ;;
            o)
                o=&quot;${OPTARG}&quot;
                cmd=&quot;cat ${f}&quot;
                decode=&quot; &quot;
                ;;
            p)
                p=&quot;${OPTARG}&quot;
                pflag=1
                ;;
            *)
                readcert_usage

                ;;
        esac
    done
    shift $((OPTIND-1))
    if [ $pflag -eq  1 ]; then
       greppat=&quot;grep  --color=auto $p | awk '{print \$2}' | &quot;
       content=$($cmd | grep $p | awk '{print $2}')
       if [ -n &quot;$decode&quot; ]; then
            content=&quot;$(echo $content | base64 -d)&quot;
       fi
    fi

    echo -e $content | openssl x509 -in /dev/stdin -noout -text
}
</code></pre>
<p>The commands as such works, but having problems in generalizing the approach using functions</p>

<p>I'd try hard to avoid building up a command line out of unquoted strings as you show.  It will in fact be prone to quoting problems, and if the input contains any sort of character that has special shell syntax the process is prone to behaving unexpectedly (and this can have security implications).</p>
<p>The first change I'd make is to remove the <code>-c</code> and <code>-f</code> options.  Don't have these functions try to run the commands themselves; instead, just have them filter whatever input they get.</p>
<pre class="lang-bash prettyprint-override"><code># prone to quoting problems
readcert -c 'kubectl get secret something -o jsonpath=&quot;...&quot;'

# one fewer level of quoting
kubectl get secret something -o jsonpath=&quot;...&quot; | readcert
</code></pre>
<p>If you can construct a fixed pipeline then many of the problems go away.  Say you can put &quot;maybe&quot; as a verb in the pipeline; then after parsing the command line, in concept you could get approximately</p>
<pre class="lang-bash prettyprint-override"><code>md5cert() {
  maybe grep something | \
  maybe print out some of the line | \
  maybe base64 decode it |
  md5sum
}
</code></pre>
<p>To pick the &quot;maybe base64 decode&quot; as an example:</p>
<pre class="lang-bash prettyprint-override"><code># Maybe base64 decode the input.  Takes one argument.  If it is &quot;yes&quot;,
# base64 decodes stdin to stdout; otherwise passes stdin to stdout
# unmodified.
maybe_base64_decode() {
  if [ &quot;$1&quot; = yes ]; then
    base64 -d
  else
    cat
  fi
}

md5cert() {
  decode=yes
  while getopt ... o; do
    case &quot;$o&quot; in
      o)
        decode=no
        ;;
    esac
  done
  ... | maybe_base64_decode &quot;$decode&quot; | ...
}
</code></pre>
<p>In similar tricks, <code>grep ''</code> (with an empty regexp) will print out a file unmodified (every line matches), as will <code>awk '{ print $0 }'</code>.  You can also include the (possibly empty) regexp in the <code>awk</code> call.</p>
<p>I might simplify the first function to:</p>
<pre class="lang-bash prettyprint-override"><code>maybe_base64_decode() { ... } # as above

md5cert() {
  pattern=''  # a regexp
  words='$0'  # an awk expression
  decode=yes

  while getopts &quot;:op:&quot; o; do
    case &quot;${o}&quot; in
      o)
        decode=no
        ;;
      p)
        pattern=&quot;$OPTARG&quot;
        words=&quot;$2&quot;
        ;;
      *)
        echo 'Usage: md5cert [-o] [-p PATTERN]' &gt;&amp;2
        return 1
        ;;
    esac
  done

  awk &quot;/$pattern/ { print $words }&quot; | maybe_base64_decode &quot;$decode&quot;
}
</code></pre>
<p>I've also skipped the bash-specific <code>function</code> and <code>local</code> keywords; this setup should work with any POSIX shell.</p>
<p>You don't specifically describe how you're using <code>grep</code> and <code>awk</code> here, but if you're reading a Kubernetes manifest, the <code>yq</code> or <code>jq</code> tools could be more robust ways of processing YAML or JSON output.  I hint at <a href="https://kubernetes.io/docs/reference/kubectl/jsonpath/" rel="nofollow noreferrer"><code>kubectl get -o jsonpath</code></a> in an example and that also could be a way to extract a value from an in-cluster object without trying to do text processing on YAML.</p>
