How to change default app for all files of particular file type through terminal in OS X?

I have a simpler way. You'll want Homebrew if you don't already have it:

/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

Install duti:

brew install duti

Now you need to find the id of the app you want to use, and assign it to the extension you want to use it for. In this example, I already use Brackets for *.sh and I want to also use it for *.md files instead of xcode.

Get the default app id for .sh files:

duti -x sh

output:
  Brackets.app
  /opt/homebrew-cask/Caskroom/brackets/1.6/Brackets.app
  io.brackets.appshell

The last line is the id.

Use this app id for all .md files:

duti -s io.brackets.appshell .md all

Edit ~/Library/Preferences/com.apple.LaunchServices.plist.

Add an entry under LSHandlers, containing the UTI (key LSHandlerContentType, e.g. public.plain-text) and application bundle identifier (LSHandlerRoleAll, e.g. com.macromates.textmate).

It looks like this in Property List Editor:

alt textalt text

To do this from the command line, use defaults or /usr/libexec/PlistBuddy. Both have extensive manpages.

For example to open all .plist files using Xcode:

defaults write com.apple.LaunchServices LSHandlers -array-add '{ LSHandlerContentType = "com.apple.property-list"; LSHandlerRoleAll = "com.apple.dt.xcode"; }'

Of course, you'd need to make sure there's not already another entry for the UTI com.apple.property-list already in there.

Here's a more complete script that'll remove existing entries for a UTI and add a new one. It can only handle LSHandlerContentType, and will always set LSHandlerRoleAll, and has hard-coded bundle IDs instead of parameters. Other than that, it should work quite well.

#!/usr/bin/env bash

PLIST="$HOME/Library/Preferences/com.apple.LaunchServices.plist"
BUDDY=/usr/libexec/PlistBuddy

# the key to match with the desired value
KEY=LSHandlerContentType

# the value for which we'll replace the handler
VALUE=public.plain-text

# the new handler for all roles
HANDLER=com.macromates.TextMate

$BUDDY -c 'Print "LSHandlers"' $PLIST >/dev/null 2>&1
ret=$?
if [[ $ret -ne 0 ]] ; then
        echo "There is no LSHandlers entry in $PLIST" >&2
        exit 1
fi

function create_entry {
        $BUDDY -c "Add LSHandlers:$I dict" $PLIST
        $BUDDY -c "Add LSHandlers:$I:$KEY string $VALUE" $PLIST
        $BUDDY -c "Add LSHandlers:$I:LSHandlerRoleAll string $HANDLER" $PLIST
}

declare -i I=0
while [ true ] ; do
        $BUDDY -c "Print LSHandlers:$I" $PLIST >/dev/null 2>&1
        [[ $? -eq 0 ]] || { echo "Finished, no $VALUE found, setting it to $HANDLER" ; create_entry ; exit ; }

        OUT="$( $BUDDY -c "Print 'LSHandlers:$I:$KEY'" $PLIST 2>/dev/null )"
        if [[ $? -ne 0 ]] ; then 
                I=$I+1
                continue
        fi

        CONTENT=$( echo "$OUT" )
        if [[ $CONTENT = $VALUE ]] ; then
                echo "Replacing $CONTENT handler with $HANDLER"
                $BUDDY -c "Delete 'LSHandlers:$I'" $PLIST
                create_entry
                exit
        else
                I=$I+1 
        fi
done