I have a bash script that should be extensible with additional functions with as little change to the script as possible.

The basic function is as follows. It loops through a list of files to check. The idea is that each check should be independent. A new check should be possible to add with the least possible change to the script as possible.

As bash is different from other programming languages, I think the way to do this is also different.

At the moment, a new check is added by creating a new script which is then added to the main script by calling it as an external command. That causes a lot of changes to the main script. As well the main script needs to accept aditional parameters to trigger the check script.

Is there any better way to do this? Any ideas?

  • Do all the checks have the same syntax? E.g., do they all take the command name and the path to check, or do they each have their own set of arguments? – Eric Renouf Dec 2 '15 at 17:33
  • Not necessarily. Let's assume we are checking csv files. And one check verifies that the file has 10 columns. Another check could verify if colum 7 is a int ( or float). And maybe in the future an additional check verifies column 4 tobe a valid iso date or of a certain string. – Gerhard Dec 2 '15 at 18:29
  • 3
    My "XY problem" meter is hovering in the red. – whatsisname Dec 2 '15 at 19:52
  • Can you describe what you are actually doing here? – user82096 Dec 2 '15 at 21:57

Put each "extension" in a separate bash script.

Come up with a special naming convention for them, like "x.*".

When your main script starts, have it first of all scan the directory for "x.*" and build a list of all matching extension filenames.

In each iteration of the loop, when you have a file to check, loop through the list of extension filenames and invoke each extension, passing it the filename of the file to check. Make any other information that filters may (or may not) need available to the filters as environment variables. Each filter uses whatever subset of that information it needs.

Of course this will not be so easy if each extension needs to communicate information back to the main script file, but you have not told us anything of that sort in the question. (Anyhow, even that is doable with special options which allow child scripts to modify the parent's environment.)

  • Problem is that the parameters to pass to the check scripts is not identical. – Gerhard Dec 2 '15 at 18:31
  • I amended my answer with this: "Make any other information that filters may (or may not) need available to the filters as environment variables. Each filter uses whatever subset of that information it needs." – Mike Nakis Dec 2 '15 at 18:33
  • 1
    ... But I like your idea with the file names. Sadly i can not upvote it, jet. Maybe that idea gets me closer to my goal. – Gerhard Dec 2 '15 at 18:39
  • 1
    I'd add to the idea: to easily "enable" and "disable" any of the extensions, make the script run (or source, as needed) only those with execute permission. – AlvaroGMJ Dec 2 '15 at 19:45
  • 1
    Also, in shell scripts, all variables are global by default. If you source a script instead of executing it, it gets access to all variables defined in the parent script (you'll have to make them independent enough to not cause conflicts, a good pattern is to unset all variables set by an "extension" script before it is done). You can probably use that to come up with a good solution. – AlvaroGMJ Dec 2 '15 at 19:46

When I have a set of related scripts, I almost always put all functions in a separate file, functions.sh. Then each script first sources it, and if it needs to, it can override functionality by just redefining some functions before calling the entry point function with the given arguments.

Example:

functions.sh:

# to be sourced
# ...
do-stuff-with-tool() {
    tool "$@"
}
tool() {
    call-default-tool "$@"
}
# ...

do-stuff-with-default-tool.sh:

#!/bin/bash
set -eu
HERE=$(dirname "$0")
. "$HERE/functions.sh"
do-stuff-with-tool "$@"

do-stuff-with-another-tool.sh

#!/bin/bash
set -eu
HERE=$(dirname "$0")
. "$HERE/functions.sh"
tool() {
    call-another-tool "$@"
}
do-stuff-with-tool "$@"

Your Answer

 
discard

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

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