Mixing function parameters, commands and command arguments in Bash functions I'm trying to write a bash function that will take a command such as xcode-select -v or brew -v that outputs a lot of extra text, and format it to my liking.  Just to further the example, say I run xcode-select -v, it will output xcode-select version 2333..  I want to be able to split this string up and only take the 2333 part so I can put it in an echo statement.  I want the same function to be able to handle the various outputs of stuff like brew -v, or git --version, etc.

get_version_number() {
    # set local variable to executed arguments that is passed in
    local command="$($@)"
    # set up temp variable and assign to global IFS variable
    OIFS=$IFS
    # set up IFS to split the string on empty space
    IFS=" "
    # read commands output into an array and store it in $array variable
    read -a array &lt;&lt;&lt; "$command"
    # clear out IFS back to what it original was for further use
    IFS=$OIFS
    # echo out array at a particular indices that should be passed in 
    echo ${array[@]}
}

# store output of this command into variable for further usage
version=$(get_version_number xcode-select -v)
echo $version


Edit 1:
Originally the idea came from me having to copy/paste these same lines within different conditional blocks...

command=$(git -v)
OIFS=$IFS
IFS=" "
read -a output_array &lt;&lt;&lt; "$command"
IFS=$OIFS
printf "Git version ${output_array[2]} is installed."

command=$(brew -v)
OIFS=$IFS
IFS=" "
read -a output_array &lt;&lt;&lt; "$command"
IFS=$OIFS
printf "Homebrew version ${output_array[1]} is installed."
The trick for splitting up the version blurb for just the version number, is to pass the values you want in before the command, and then shift them off $@.
you have done a relatively unfamiliar-to-me parsing mechanism with the resetting the field separators, etc. Using bash as a parser is a problem for me (and I've never hated myself enough to try....).
I would set up a function that takes a co-ordinate of a version as a line/word combination, and rely on out-of-bash tools to do it......
I will probably get nailed for starting 4 sub-processes, but head, tail, and cut are small.... right?  (Forgive me already, you won't be calling this in a tight loop, will you? You're already doing that a bit with the bash $( ...) operator...)
get_version_number() {
    local line=$1
    shift
    local word=$1
    shift

    # echo Line $line Word $word and Commend $@

    # set local variable to executed arguments that is passed in
    echo &quot;$( $@ | head -$line | tail -1 | cut -d ' ' -f $word)&quot;
}

Then you would call it like:
gitver=$(get_version_number 1 3 git --version)
perlver=$(get_version_number 2 4 perl -version)

echo Git and Perl are $gitver and $perlver respectively

which for me, produces:

Git and Perl are 1.7.1 and v5.10.1 respectively

This also allows you to do things like get the redhat version as
rhelver=$(get_version_number 1 7 cat /etc/issue)
javaver=$(get_version_number 1 3 java -version)

and even things like the current time 23:45:08 ;-)
time=$(get_version_number 1 4 date)


Some notes:

historically, it is 'expensive' to start lots of child processes. It still is a problem, but not quite as bad as it was. Doing that hundreds or thousands of times may add up to seconds of time wasted. If you can avoid creating child processes, do it.... but, sometimes it's just easier to be lazy than to be super-bash-smart.
I create an additional 4 processes (actually 5) each time you call the function. One for the $( ... ), one for the $@ inside that, one for head, one for tail, and one for cut. That is almost excessive.... but if you are calling this 100 times, then it's OK, if you are calling it 1000 times, you will be able to save seconds by doing it differently.
the $( ... ) operator is formally called the Command Substitution. What it means is that everything inside the structure is run as if in a 'child' bash process.... (so a new process is created, and the output is substituted in place of the command)
what the shift operator does is take $@ and remove the first item.... so, your function called as get_version_number 1 3 git --version gets 4 parameters, 1, 3, git and --version. We copy $1 off as $line, and then shift $@, so there are now only 3 parameters in $@. We then copy $1 again (but because of the shift, it is a different value) as $word, and then shift again to remove it. We are left with just git and --version as the parameters.

If you wanted, for example, to save one process each time, you could instead do:
get_version_number() {
    local line=$1
    shift
    local word=$1
    shift
    GOTVERSION=&quot;$( $@ | head -$line | tail -1 | cut -d ' ' -f $word)&quot;
}

get_version_number 1 3 java -version
javaversion=$GOTVERSION

That saves using the $( .... ) and echo combination, so you save a process, but the code is a bit more complicated.

Edit 2.
'Obviously', what I suggest you do is not necessarily the best thing. Your code was working fine, and the mechanism will be faster (slightly) than mine because it does not do the additional 4 processes and keeps the logic inside bash internal commands.
Here is my 'shift' system applied to your code:
get_version_number() {
    local word=$1
    shift
    # set local variable to executed arguments that is passed in
    local command=&quot;$($@)&quot;
    # set up temp variable and assign to global IFS variable
    OIFS=$IFS
    # set up IFS to split the string on empty space
    IFS=&quot; &quot;
    # read commands output into an array and store it in $array variable
    read -a array &lt;&lt;&lt; &quot;$command&quot;
    # clear out IFS back to what it original was for further use
    IFS=$OIFS
    # echo out array at a particular indices that should be passed in 
    echo ${array[$word]}
}

and you would call it with the word-number for the version as the first argument:
gitver=$(get_version_number 3 git --version)

But this does not allow you to find versions on multi-line outputs.....