1

Okay, so I'm kinda stumped here.

I'm in the midst of a deep-dive into BASH, for the purposes of writing some automation scripts for my employer. Also, full disclosure here: I'm a web guy; hitherto I've known JUST enough CLI to operate git.

My issue is, about half the staff are using MacOS, the other half are using GitBash, and it seems there are different flags supported (or, more relevantly, not supported) on the two different BASH instantiations. Further conundrum: what with everyone working from home and the world ending and all, I cannot reliably demand every one of our staff "switch to distro X"/"upgrade to version Y".

Now, I know how to test if a given program is installed (though, I confess: I'm not crystal-clear why one is preferable to the other, and please: correct me if either is a terrible way of handling this), in the forms of:

type foo >/dev/null 2>&1 || { echo >&2 "COMMAND NOT FOUND"; }

...and...

[ -x "$(command -v foo)" ] || echo 'COMMAND NOT FOUND'

...but in my specific case, BOTH platforms HAVE foo installed, but, as a for-instance, only MacOS has a -b/--bar modifier flag. So, how do I test to see if a given FEATURE of a command is supported? Every time I try to pass a flag to one of the tests, the program PERFORMING the test seems to believe it's directed at IT, ignores it entirely, or errors out.

How can I test to see if foo -b/foo --bar is a valid/installed/accessible command?

Update/Answer

Since the general consensus presented in the well-reasoned and honestly excellent answers received below appears to be a hybrid of "no, one cannot", punctuated with "there's simply too many factors to be able to reliably glean anything resembling conclusive, useful data", I'm closing out the question.

My intention here was to ascertain what the correct approach to employ was to verify the presence of a potentially non-existent flag between two different platforms - known platforms, fortunately, in my case - and the appropriate tact in this case would seem to be the one I'm currently taking: maintain two separate scripts, one for each platform.

Thank you to all who took the time to respond! It's much appreciated.

NerdyDeeds
  • 121
  • 5
  • 2
    Are you at all concerned about whether foo -b, if it's supported by both architectures, means the same thing? IMHO, it would be better to write a script for macOS, and another for whatever GitBash is, rather than trying to dynamically change the behavior of a single script. Alternatively, encapsulate the relevant behaviors in shell function libraries that you load depending on architecture. – Kusalananda Aug 12 '20 at 06:03
  • @Kusalananda - Yes, I can. Indeed, that's what I'm doing now. But this really is less about the automation and more about my understanding of BASH itself. The automation is what PROMPTED the question, but the question ITSELF is simply "Is there a way I can do this thing?" I know there's a bajillion shell flavors out there, but even if it's so simple as telling the user, whoops! You're missing this feature. Wanna upgrade your shell version at this time? >Y/n $1 It's simply the knowledge I lack right now, and I cannot seem to find any sources that suggest, "Oh, sure! That's possible!" – NerdyDeeds Aug 13 '20 at 03:24

1 Answers1

1

In a useful and reliable way, you probably can't. You basically need to test each command individually to see what it does. (The command "echo" is a particularly bad case of this. There are a lot of variations.)

What you can do, is check version numbers and operating system.

For BASH, try

bash --version | head -1

or

bash_version="$( bash --version | head -1|sed -e 's/.* version //;s/ .*//' )"

or just use the predefined symbol $BASH_VERSION

For the operating system, uname -s is a good start, and other options might give you more details.

Once you have these, you can start writing conditional code as needed.

Having said all that... for your specific case of a foo command that may or may not take a --bar option: Figure out what the two versions do with matching command lines that are otherwise safe to run. For instance, if both versions of foo report the first invalid option, try writing something like:

output="$( foo --bar --somethingtotallyinvalid 2>&1 )"

and then figuring out what is in variable output. Of course, in this case, it is liable to be the valid option list. If so, you might consider:

output="$( foo --somethingtotallyinvalid 2>&1 | grep -e --bar )"
muru
  • 72,889
David G.
  • 1,369
  • 2
    The behaviour here isn't dependent from the version of the shell. The question is misleadingly written. The differences that one encounters between MacOS bash and Git Bash on Windows are differences in external programs, in general the differences between BSD flavours of tools and GNU flavours of tools. That's asked about over and over on this WWW site. A few examples: https://unix.stackexchange.com/q/170793/5132 https://unix.stackexchange.com/q/138573/5132 https://unix.stackexchange.com/q/162607/5132 https://unix.stackexchange.com/q/188447/5132 – JdeBP Aug 12 '20 at 07:26
  • @JdeBP, macOS's bash is also an ancient one which is missing many of the more modern bash features. – Stéphane Chazelas Aug 12 '20 at 09:48
  • 1
    Some, not many; the questioner hasn't stated how many people are using a later version of bash (again something that comes up time and again on this WWW site, including just yesterday at https://unix.stackexchange.com/q/603906/5132); and assuming what people are using, from a question that does not say, and gets the shell mixed up with the programs spawned by the shell, is unjustified. In any case that is irrelevant to the "different flags" on external programs in the question here, which is nothing at all to do with shell versions. – JdeBP Aug 12 '20 at 11:35
  • 1
    While the bash version and external program versions are different, the systems will likely be consistent. If the bash is MacOS bash, then the external programs will probably be the MacOS flavor, and vice versa. – David G. Aug 12 '20 at 14:49
  • 1
    Is this even necessary? Do your automation scripts really have to use EVERY option of EVERY command? Wasn't this solved long ago by https://www.gnu.org/software/autoconf/ ? – waltinator Aug 12 '20 at 20:17
  • Okay, as a for-instance here: ssh-add -K <KEYFILE>. Per the man pages for ssh-add in GNU bash, version 5.0.18 (x86_64-apple-darwin17.7.0), the default on the Macs their respective users are running, it states "-K - When adding identities, each passphrase will also be stored in the user's keychain." In git-bash (GNU bash, v. 4.4.23 (x86_64-pc-msys) - also default-installed from IT's system image, we get ssh-add: unknown option -- K.I'm sure I can manhandle keychain into the version we're running, but I CANNOT RELIABLY MAKE EVERYONE ELSE. Is there really no way to test to see if -K exists? – NerdyDeeds Aug 13 '20 at 03:16
  • Side-note: I'm aware there are other ways around this dilemma... mainly, though, for my own edification here, I'm trying to ascertain if there's a way I can CHECK a command to see if it's "parsable"/"runnable" without actually running it first, then have the automation script decide what to do next based on the results of said test. – NerdyDeeds Aug 13 '20 at 03:20
  • @NerdyDeeds In general, No. In practice, many commands have a "--version" option, which can tell you a lot. For instance, try cp --version Other commands can be run in a quick innocuous manner, that will give you information. For instance, if neither a nor b exist, then writing cp --silly a b and capturing the output is a method to determine if cp understand the option --silly. Or you could make a scratch file and scratch filename to actually copy if the option is known, and test $?. – David G. Aug 13 '20 at 18:23