Bash – How does ‘Open with’ a custom executable in Linux work

bashmime-typesruby

I have a file called foo.txt. I want to associate my own program with the mime-type .txt so that my program opens a terminal and shows the contents of foo.txt as standard output. I would prefer Ruby, but BASH scripting will also be OK.

An working example: I can open an HTML file with firefox. I want to open txt files with my own executable the same way.

I can't figure out how can I actually get it working?

Example 2: I can open a .txt file with Geany/Mousepad/Atom/Code etc.
Let's suppose I have made a tool just like mousepad. How should my program handle the .txt mimetype?

So far I have made a small GUI program with Ruby and made it executable and tried to open foo.txt with my program (I used the Nemo file manager). I have captured arguments, and stdins in my Ruby program so it will show the Argument and STDINs if any. But my program doesn't even show up the window if I open a .txt file with it!

How am I supposed to achieve the result?

Best Answer

Introduction

When a file is opened with an application, the file is just passed to the application as an argument.

So when you open firefox-nightly located in /bin/ with p.html located in /home/user/, it's basically similar to run /bin/firefox-nightly /home/user/p.html.

Creating an Executable

As mentioned in the question:

So far I have made a small GUI program with Ruby and made it executable and tried to open foo.txt with my program (I used the Nemo file manager).

Let us create a Ruby program as asked by the OP that will copy the contents of a file passed as an argument to /tmp/tempfile-#{n}. Note that any programming language will work if it can accept command line arguments.

#!/usr/bin/env ruby

# Errors
ERR_NO_FILE = 2

FILE = $*[0]

begin
    tempfile, counter = File.join(%W(/ tmp tempfile)), 0
    tempfile.replace(File.join(%W(/ tmp tempfile-#{counter += 1}))) while File.exist?(tempfile)
    IO.write(tempfile, IO.read(FILE))
rescue Errno::ENOENT
    exit!(ERR_NO_FILE)
rescue Interrupt, SystemExit, SignalException
    exit!(0)
rescue Exception
    abort($!.backtrace.join(?\n))
end if FILE

And let's call our program copycat.rb, and move it to /tmp/ directory.

We can surely run the program on a terminal like this:

/tmp/copycat.rb /tmp/AFile

A this will copy all the contents of /tmp/AFile to /tmp/tempfile-#{n} Where #{n} is the count in case any duplicate tempfile exists.

Creating an Application Entry

Now to open this with our program from the file manager, we need to create an Application entry. To do that, we have 2 options. The first options is:

Create a file called copycat.desktop in $HOME/.local/share/applications, with the following content:

[Desktop Entry]
Version=1.0
Type=Application
Name=CopyCat
Comment=Copy the contents of a file to /tmp/tempfile#{n}
Exec=/tmp/copycat.rb %u
Icon=edit-copy
Path=
Terminal=false
StartupNotify=false
Actions=
Categories=Copy;Utility

Don't forget to add the %u option to the line starts with Exec.

Testing

Well, to test, let's create a simple file called with the content 'hello world' or anything you want. Open your file manager, and click your secondary mouse button on the file, and select "Open With" or similar option. Because it's GUI related, I will add some sample pictures.

  1. Nautilus, "Open With Other Application":

    Nautilus, "Open With Other Application"

  2. Nautilus, "View All Applications":

    Nautilus, "View All Applications"

  3. "CopyCat":

    "CopyCat"

  4. When done, you can see the tempfile-#{n} created in /tmp/

    enter image description here

The file manager I used here is Nautilus, but this should work with other file managers as well, just the text might differ.

The second option is to make the application available for all users. To do that, you have to move the file from $HOME/.local/share/applications/copycat.desktop to /usr/share/applications and change the ownership to root.

This is how the open with a custom executable works in Linux. A similar GUI app can be created and opened in the same way.

Related Question