4
\$\begingroup\$

I am writing a bash script to mount openshift service accounts into kubernetes objects. The right secret to use is highlighted in this text:

$ oc describe sa sa-build-webhook-realworld
Name:                sa-build-webhook-realworld
Namespace:           your-eng2
Labels:              app=sa-build-webhook-realworld
Annotations:         <none>
Image pull secrets:  sa-build-webhook-realworld-dockercfg-4qz9g
Mountable secrets:   sa-build-webhook-realworld-token-bqtnw
                     sa-build-webhook-realworld-dockercfg-4qz9g
Tokens:              sa-build-webhook-realworld-token-bqtnw
                     sa-build-webhook-realworld-token-k7lq8
Events:              <none>

I want the code to be reasonably robust so I am thinking of this as a job for awk where I need "anything in column 2 that is a 'Mountable secret' that isn't the docker secret". Here is the logic I have come up with:

MOUNTABLE_SECRETS='Mountable secrets:'
SECRET_NAME=$(\
   oc describe sa sa-build-webhook-realworld \
   | sed $(printf 's/./&,/%s' ${#MOUNTABLE_SECRETS}) \
   | awk  'BEGIN{FS=OFS=","} {if ($1 ~ /^[ \t]*$/) $1=ch; else ch=$1} 1'  \
   | grep "$MOUNTABLE_SECRETS" \
   | sed 's/[, ]*//g' \
   | awk -F':' '{print $2}' \
   | grep -v docker \
   | grep token)
echo "SECRET_NAME=$SECRET_NAME"

Basically, I insert a character just beyond the width of that phrase to cut the table in half, copy cells on the left into blanks below, then select the second column then grep what I am looking for.

To my mind, it breaks things into pieces that can be understood. It works, but past experiences have taught me that someone looking to maintain that may not be best pleased. Since performance is not an issue what I am really aiming for is maintainability. I also want portability and I am looking to stick with to typical bash and coreutils tools.

How might I improve that script?

\$\endgroup\$
  • \$\begingroup\$ macOS comes with Python 2 pre-installed. \$\endgroup\$ – 200_success Jan 23 at 18:53
  • \$\begingroup\$ fair enough but i am disinterested in worrying about the three major OSes and major linux distros. clearly someone submitting answers in whatever they think is a good fit works for me. \$\endgroup\$ – simbo1905 Jan 23 at 18:55
  • \$\begingroup\$ Please do not update the code in your question to incorporate feedback from answers, doing so goes against the Question + Answer style of Code Review. This is not a forum where you should keep the most updated version in your question. Please see what you may and may not do after receiving answers. \$\endgroup\$ – Zeta Jan 24 at 6:30
  • 1
    \$\begingroup\$ cool was the comment also a bot or handcrafted? my initial reading of it was that it was a bit harsh. i totally get why edits are not a good thing having read the meta post so i have absolutely no quibble over the bot reverting changes. yet i had a strong negative emotional response to being 'told off' when trying to share the joy of the solution. i would recommend something like "Thanks for attempting to refine your question by incorporating feedback from answers, yet doing so goes against the Question + Answer style of Code Review so we automatically revert such changes. Please see ..." \$\endgroup\$ – simbo1905 Jan 24 at 6:59
  • 1
    \$\begingroup\$ @simbo1905 It's from a list of common comment. Sorry if it was a bit harsh, that was not my intention. Feel free to add the "Thanks for attempting …" to the post, that would be a nice addition :) \$\endgroup\$ – Zeta Jan 24 at 8:11
5
\$\begingroup\$

Your idea to transform the table so that the implied keys explicitly appear on every row is an interesting one, but I think that it is overcomplicated.

The backslashes to indicate continuation lines are actually superfluous here, since an unfinished $( substitution automatically causes the command to be incomplete. Similarly, ending a line with a | pipe would also cause the command to be continued, so that would be a better convention to follow than putting the | at the beginning of the following line.

In general, any combination of sed, awk, and grep would be better expressed using just an AWK script. The AWK script below reads a key and value if there is a colon on a line, or just a value if there is no colon.

SECRET_NAME=$(
    oc describe sa sa-build-webhook-realworld |
    awk -F: '
        $2  { KEY=$1 ; VALUE=$2; sub("^ *", "", VALUE); }
        !$2 {          VALUE=$1; sub("^ *", "", VALUE); }
        KEY=="Mountable secrets" && VALUE !~ /docker/ { print VALUE }
    '
)
\$\endgroup\$
  • 1
    \$\begingroup\$ it’s a work of art! \$\endgroup\$ – simbo1905 Jan 23 at 19:25
  • 1
    \$\begingroup\$ can speed it up about 3x by not copying or trimming unused values: awk -F': *' '$2 { KEY=$1 } KEY=="Mountable secrets" && $NF !~ /docker/ { print $NF }' \$\endgroup\$ – Oh My Goodness Jan 23 at 23:30
  • 2
    \$\begingroup\$ @OhMyGoodness why not a separate answer? \$\endgroup\$ – simbo1905 Jan 24 at 0:17
  • 1
    \$\begingroup\$ It's only a refinement of what @200_success wrote; the algorithm is the same and he took the trouble to write good advice besides. He deserves the answer credit. \$\endgroup\$ – Oh My Goodness Jan 24 at 1:06
  • \$\begingroup\$ okay i accepted the answer, i went with the -F' *' enhancement that allowed me to remove both sub calls. what an amazing thing awk is i am going to take the advice of not mixing awk with sed and grep ever. also the tip about sub shell continuations and even the formatting of awk blocks rocks. this experience has been a joy i really appreciate both your time you folks are awesome! \$\endgroup\$ – simbo1905 Jan 24 at 6:14

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.