12

I need to batch change the application associated with certain files via the command line. I'm not to change the file association for a certain file extension, I'm actually looking to target specific files to open in a different application than the default association for that file type. I do not want to change the default application for this file extension overall, just for the specific files I target.

Right now, I'm selecting all the files i want to change in finder, hitting option+command+i to open up get info for multiple files, and the changing the application for those files. It's kind of annoying.

5 Answers 5

8

This information is stored in the file's resource fork (Wikipedia). These resource forks are exposed as extended attributes (Wikipedia):

$ ls -l@ somefile.txt 
-rw-r--r--  1 danielbeck  staff  0 18 Mär 19:00 somefile.txt

# setting non-default application using Finder

$ ls -l@ somefile.txt 
-rw-r--r--@ 1 danielbeck  staff  0 18 Mär 19:01 somefile.txt
        com.apple.ResourceFork  1338 

Editing from scratch is probably quite painful -- lots of binary data:

$ xattr -p com.apple.ResourceFork somefile.txt 
00 00 01 00 00 00 05 08 00 00 04 08 00 00 00 32
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 04 04 00 00 00 32 2F 55 73 65 72 73 2F 64
61 6E 69 65 6C 62 65 63 6B 2F 41 70 70 6C 69 63
61 74 69 6F 6E 73 2F 53 75 62 6C 69 6D 65 20 54
65 78 74 20 32 2E 61 70 70 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 01 00 00 00 05 08
00 00 04 08 00 00 00 32 0C 00 00 00 C0 05 00 00
00 1C 00 32 00 00 75 73 72 6F 00 00 00 0A 00 00
FF FF 00 00 00 00 19 00 00 00

But you can treat these resource forks like files. For example:

$ open somefile.txt # opens in Sublime 2
$ cp somefile.txt/..namedfork/rsrc openInSublime2rsrc
$ open otherfile.txt # opens in TextEdit
$ cp openInSublime2rsrc otherfile.txt/..namedfork/rsrc
$ open otherfile.txt # opens in Sublime 2

/..namedfork/rsrc is how the resource fork is exposed to POSIX applications (i.e. probably everything you do in Terminal).

So you just need to create one "template" file from an existing resource fork (in this example openInSublime2rsrc), and you can copy it to your other files afterwards.

5
  • 1
    This solution worked until Lion. Copying to file/rsrc gives me a ": Not a directory" error. Back to square one :(
    – Rob
    Aug 7, 2011 at 3:39
  • 1
    @Rob Try using somefile.txt/..namedfork/rsrc instead. somefile.txt/rsrc has been deprecated a while ago.
    – Daniel Beck
    Aug 7, 2011 at 9:48
  • Daniel Beck-you are a lifesaver, thank you so much.
    – Rob
    Aug 7, 2011 at 16:07
  • You don't need to edit the resource forks directly-see my answer below, but the summary is that you can use utilities called Rez and DeRez to edit resource forks. Since these are supported developer tools, you're less likely to have a problem.
    – mauvedeity
    Oct 8, 2011 at 8:38
  • You can get a (more) human friendly value (JSON) with : xattr -p com.apple.LaunchServices.OpenWith /path/to/file | xxd -r -p - | plutil -convert json -o - -
    – mems
    Nov 8, 2020 at 18:24
5

Picking up from Daniel Beck's answer above, this information is indeed stored in the file's resource fork. Apple provides two utilities, called "Rez" and "DeRez" with the developer tools, which allow you to manipulate resource forks. In particular, you can push a resource fork into a file with Rez.

To change the association of a single file from the command line, first create a file of the right type, and manually change its association to the application you want it to open in. This creates the resource fork in the file - if you don't do this, there'll be no information to copy out. Then, pull out the resource fork with DeRez, like this (assuming a file foo.txt, and that the application you want to use is Firefox.app).

DeRez foo.txt > foo.r

This will create a file called foo.r which is the decompiled resource fork as a text file. It will look something like this:

data 'usro' (0) {
    $"0000 001A 2F41 7070 6C69 6361 7469 6F6E"            /* ..../Application */
    $"732F 4669 7265 666F 782E 6170 7000 0000"            /* s/Firefox.app... */
    $"0000 0000 0000 0000 0000 0000 0000 0000"            /* ................ */

You can edit this if you want to create one from scratch, but you have to get the format exactly right or it won't work. It's just hex-encoded characters describing the path to the app bundle you want, terminated with a zero.

You might see a message saying that the resource fork is empty and uninitialised. If so, you haven't changed the per-file association on the source file, so you need to go do that, then re-run the DeRez command.

Once you have this, you can push this into another file as follows (assuming bar.txt exists):

Rez foo.r -a -o bar.txt

This updates bar.txt in place with the resource fork from foo.r.

To check it worked OK, since neither Rez nor DeRez print error messages, just do this:

DeRez bar.txt

You should see the same information as before. After all that, just open the file bar.txt as you normally would, and it should open in the correct application, not the default one.

To do a batch change, once you have the .r file, then you can use a standard wildcard expansion like this:

Rez foo.r -a -o *.txt

That'll do all the files that match the wildcard.

I have done this on 10.7, but it's my understanding that this works on earlier machines too.

2
  • Interesting information on these tools. Still, it looks like these tools do nothing that accessing ..namedfork/rsrc doesn't also do, correct? You trade requiring knowledge about (semi) internals for knowledge about specific tools — I'm not convinced this is better.
    – Daniel Beck
    Oct 8, 2011 at 10:03
  • @DanielBeck You are correct, as far as I know. However, as was said upthread, the internals information changed with Lion, whereas these are stable dev tools that should be version-independent. Personally, I think the internals stuff is interesting, but the tools are more likely to work cross-platform, and I'd rather use the supported tools.
    – mauvedeity
    Oct 8, 2011 at 10:31
4

I did it using xattr (it works perfectly on APFS volume)

xattr -wx com.apple.LaunchServices.OpenWith \
"`xattr -px com.apple.LaunchServices.OpenWith FILEWITHGOODTYPE`" FILETOCHANGE

It works by copying the OpenWith extended attribute from a file that is already associated with the right app, to a file that is not.

1

You say you want to "batch change" the application associated with a given (sub-)set of files, of a given type. sub-set because you don't want to change all instances of that file type to that new application.

However, there is no easy way to do this. The way how LaunchServices findout which application should be told to open a file is a multistage process, and depends on settings with different scopes (user, system and so on).

But - you could use open on the commandline and tell it to use a specific app this time. This would not change any association, but it would achieve what you say you want, namely open a set of files in a specific application:

open -a <appbundle> <somefile> <anotherfile>

like

shiny:t fl$ ls -l
total 1848
-rwxr-xr-x  1 fl  staff    1795 Mar 18 20:03 distribution.pl
-rw-r--r--  1 fl  staff  939264 Mar 18 20:03 objectreport.txt
shiny:t fl$ open -a TextWrangler distribution.pl objectreport.txt

and, going totally away from the command line: take a look at this utility: http://michelf.com/software/magic-launch/

2
  • In your specific example, open -a TextWrangler * would be even quicker.
    – Daniel Beck
    Mar 18, 2011 at 19:16
  • yes, but that would add the layer of shell wildcard expansion to the explanation, which would make the example less understandable :-) not so bad for open, but there are other tools that just invite wildcard problems... Mar 18, 2011 at 19:21
0

You can use tool duti

example, set vscode for .txt format:

duti -s com.microsoft.VSCode .txt all
1
  • Your answer could be improved with additional supporting information. Please edit to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers in the help center.
    – Community Bot
    Sep 12, 2022 at 21:22

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .