6
\$\begingroup\$

This code and updates are available on Github.

I've written a small utility to dump the variables that are assigned in a bash script.

Please note:

  • This script depends on the shfmt and jq apps.
  • I am not looking to make this script posix compliant, only bash specific.

Some possible areas for improvement:

  • Can the jq query be improved?
  • Are there other entries in the json output of shfmt that I can look for variable assignments.
  • Any gotchas I'm missing?

As I type out this question, it occurs to me that showing variables used in a script would be a good thing to allow as an option. I'll look into it, but if anyone has any ideas in this respect, I'm interested in hearing your input.

#!/bin/bash
#------------------------------------------------------------------------------
warn() { printf '%s\n' "$*" >&2; }
die() {
 (($#)) && warn "$*"
 exit 1
}
command_exists() { command -v "1ドル" &> /dev/null; }
#------------------------------------------------------------------------------
_showvars() {
 local filename=1ドル
 [[ -f $filename ]] || die "$filename is not a file or does not exist."
 [[ -r $filename ]] || die "$filename is not readable."
 jq_query='[ .. | select(.Assigns?) | .. | select(.Name?) | .Name.Value ] | unique[]'
 # shellcheck disable=SC2046
 printf ' %s\n' $(shfmt -tojson < "$filename" | jq "$jq_query" | tr -d '"')
}
#------------------------------------------------------------------------------
(($#)) || {
 cat << EOH
showvars is a simple script that shows
what variables are assigned in a bash
script
usage: showvars filename [filename ...]
EOH
 exit 1
}
for r in shfmt jq; do
 command_exists $r || die This script depends on $r and it is not found.
done
for f in "$@"; do
 printf '\n%s:\n' "$f"
 _showvars "$f"
 shift
done
echo

Edit: Fixed copy-paste error with (($#))... line Edit: Removed code that removes lower case variables (an artifact from another code solution)

Sara J
4,15612 silver badges37 bronze badges
asked Jul 31, 2019 at 22:42
\$\endgroup\$
1

1 Answer 1

2
\$\begingroup\$

The difference between $* and $@

warn() { printf '%s\n' "$*" >&2; }

This is equivalent to the simpler:

warn() { echo "$*" >&2; }

The printf version is useful if you want to produce one line per parameter, and in that case you must use "$@" instead of "$*". Also in callers of warn.

Use -r for raw output of jq

Instead of jq "..." | tr -d '"' a better way is jq -r "...".

An alternative to printf and a sub-shell

Instead of this:

 # shellcheck disable=SC2046
 printf ' %s\n' $(shfmt -tojson < "$filename" | jq "$jq_query" | tr -d '"')

I recommend this way (and no need to disable shellcheck):

shfmt -tojson < "$filename" | jq -r "$jq_query" | sed -e 's/^/ /'

Use a bit more double-quotes

You did a good job of double-quoting the most important things. I would double-quote here too:

command_exists $r || die This script depends on $r and it is not found.

To train good habits:

command_exists "$r" || die "This script depends on $r and it is not found."

"$@" is the default list for for

Instead of for f in "$@"; do, you can simply write for f; do.

The shebang

In some systems Bash is not in /bin/bash. For that reason I prefer to use #!/usr/bin/env bash as the shebang, it makes the script more portable.

Simplify the readable file check?

 [[ -f $filename ]] || die "$filename is not a file or does not exist."
 [[ -r $filename ]] || die "$filename is not readable."

The -r implies -f. I would simplify this to one line:

[[ -r $filename ]] || die "$filename is not a readable file."

Use echo when it's good enough

Instead of printf '\n%s:\n' "$f" I would write:

echo
echo "$f:"

Here-documents

EOH is an unusual symbol for the here-document marker. That's not a problem, but I think the less surprising elements in a script, the better. I don't see a good reason to not call this EOF as usual.

Your questions

Some possible areas for improvement:

  • Can the jq query be improved?
  • Are there other entries in the json output of shfmt that I can look for variable assignments.

Unfortunately I'm not able to answer these. You might want to wait for another reviewer who can!

answered Aug 1, 2019 at 6:49
\$\endgroup\$
1
  • \$\begingroup\$ Thank you. I implemented some of your suggestions, while others prompted a different change. I've included details in my question. \$\endgroup\$ Commented Aug 1, 2019 at 18:14

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.