Search code examples
macosbashshellhomebrewhomebrew-cask

Shell script loop over array passed as argument to multi-argument function?


I am trying to do something like this:

function install {
  cmd=$1
  shift
  for pkg in "$@";
  do
   if $cmd $pkg; then
    echo "Installed $pkg"
   else
    echo "Failed to install $pkg"
   fi
  done
}

brews=(git node scala sbt zsh caskroom/cask/brew-cask)
casks=(dropbox google-chrome spotify)

install 'brew install' $brews
install 'brew cask install' $casks

However, this only works for the 1st element of each of the arrays. Why is not picking up rest of the array elements??


Solution

  • Revised Question

    Replace:

    install 'brew install' $brews
    install 'brew cask install' $casks
    

    With:

    install 'brew install' "${brews[@]}"
    install 'brew cask install' "${casks[@]}"
    

    To understand why, observe:

    $ brews=(git node scala sbt zsh caskroom/cask/brew-cask)
    $ echo $brews
    git
    $ echo "${brews[@]}"
    git node scala sbt zsh caskroom/cask/brew-cask
    

    As you can see, under bash, $brews references just the first element of an array. By contrast, "${brews[@]}" will expand to all members of the array with each member a separate word.

    Original Question

    Replace:

    if $cmd $2; then
    

    With:

    if $cmd "$pkg"; then
    

    Similarly replace references to $2 to $pkg in the echo statements.

    Aside

    While you are at it, just in case any arguments contain spaces, replace:

    for pkg in $@;
    

    With

    for pkg in "$@";