How can I change the default app for all files of a particular file type through the Terminal in OS X?
-
Not a dupe, even though I kind of answered it there. Sorry about that.– Daniel Beck ♦Apr 21, 2011 at 17:25
-
For power use, I like the accepted answer under a more recent Super User question, Is there a faster way to change default apps associated with file types on OS X?. For simplicity, I like Daniel's answer below.– Graham PerrinApr 29, 2012 at 13:08
2 Answers
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
-
3Would upvote this 50 times if I could. Great info. Worked like a charm for me in El Capitan. Jul 8, 2016 at 21:59
-
2Working in Sierra too. Extra tip: UTIs are a pain, but you can use "mdls -name kMDItemContentType <file>" to find the UTI for a given file (and therefore extension).– AdrianNov 14, 2016 at 3:22
-
6If you haven't already associated an app with something this way but know the name of your the app, you can do
osascript -e 'id of app "$appName"'
to get the id of any app installed on your system Aug 11, 2017 at 12:14 -
3Just for the reference: combining tip from @GrayedFox with duti:
duti -s $(osascript -e 'id of app "Visual Studio Code"') .md all
Dec 11, 2018 at 16:50 -
And by the way, the id for Visual Studio Code is
com.microsoft.VSCode
– FooBarJan 13, 2021 at 10:27
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:
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
-
3The easiest way is probably to
x=~/Library/Preferences/com.apple.LaunchServices.plist; plutil -convert xml1 $x; open -a TextEdit $x
and copy and paste those LSHandlers entries. To get the bundle identifier you can doosascript -e 'bundle identifier of (info for (path to app "TextEdit"))'
.– LriApr 22, 2011 at 6:24 -
@Lri In a way, yes, but this question is specifically about the command line. I figured that TextEdit (or Property List Editor / Xcode) doesn't qualify; I just copied over that part with Property List Editor from my other answer for illustration purposes. Useful remark on the bundle identifier.– Daniel Beck ♦Apr 22, 2011 at 8:40
-
Credit to Daniel, I borrowed from this for an answer to a question in Ask Different, Can Finder and the “open” command treat files with .sh or other typical extensions just like .command files?. Apr 29, 2012 at 13:11
-
If there does exist an alternative entry for the UTI, would you agree that "command line removal of a single dictionary from an array may be unnecessarily difficult"? Apr 29, 2012 at 13:14
-
1@GrahamPerrin It is unnecessarily difficult because
defaults
doesn't seem to be capable to do it, and it requires a fewPlistBuddy
calls. But it's possible to do it in a reusable shell script.– Daniel Beck ♦Apr 29, 2012 at 18:58