Best way to check in bash if Command Line Tools are installed?

Using bash, I want to check if Command Line Tools are installed.

Currently they are and when I type xcode-select --install I get:

xcode-select: error: command line tools are already installed, use "Software Update" to install updates It appears Homebrew is already installed. If your intent is to reinstall you should do... blah blah blah

Basically my problem is that I have several methods to check in bash (using if / fi) but I don't know which solution is the best one.

1) I can do xcode-select -p and that returns the path /Library/Developer/CommandLineTools but then how I should build the if statement? I don't know what will be presented when CLT are not installed.

2) I can do xcode-select --version. Should I then grep for a phrase version since I get

xcode-select version 2343.

3) I can do which xcode-select but again, in all cases I'm not sure how the if should look like. I also think that grep is not the best way, since in the future the output may be different in future version of OSX.

To sum up I would like something like

#!/bin/bash
if [ no idea ]; then
    #installed, nothing to do...
else
    xcode-select --install
fi

Thanks for any suggestions.


Solution 1:

if type xcode-select >&- && xpath=$( xcode-select --print-path ) &&
   test -d "${xpath}" && test -x "${xpath}" ; then
   #... is correctly installed
else
   #... isn't correctly installed
fi

Strangely, the --print-path isn't documented in old Xcode versions but is working as -print-path. On the other hand, the -p option doesn't have this compatibility.

Solution 2:

Just because code-select returns a valid path doesn't mean the command line tools are installed:

$ xcode-select -p
/Applications/Xcode.app/Contents/Developer
$ if type xcode-select >&- && xpath=$( xcode-select --print-path ) &&
    test -d "${xpath}" && test -x "${xpath}" ; then echo "installed" ; fi
installed
$ xcode-select --install
xcode-select: note: install requested for command line developer tools

Thus, a more accurate check is to use xcode-select to try and install the CLT with the following:

if xcode-select --install 2>&1 | grep installed; then
  echo installed;
else
  echo not installed, installing;
fi

If it's not installed, it will prompt for installation as your example shows, but without a separate line for the xcode-select --install.

Solution 3:

Yet another approach would be to use pkgutil

if      pkgutil --pkg-info com.apple.pkg.CLTools_Executables >/dev/null 2>&1
then    printf '%s\n' "CHECKING INSTALLATION"
        count=0
        pkgutil --files com.apple.pkg.CLTools_Executables |
        while IFS= read file
        do
        test -e  "/${file}"         &&
        printf '%s\n' "/${file}…OK" ||
        { printf '%s\n' "/${file}…MISSING"; ((count++)); }
        done
        if      (( count > 0 ))
        then    printf '%s\n' "Command Line Tools are not installed properly"
                # Provide instructions to remove and the CommandLineTools directory
                # and the package receipt then install instructions
        else    printf '%s\n' "Command Line Tools are installed"
        fi
else   printf '%s\n' "Command Line Tools are not installed"
       # Provide instructions to install the Command Line Tools
fi