How to easily open files and URLs from the command line

David A. Wheeler

2018-10-07 (original 2010-07-06)

Nearly all operating systems have a simple command to open up a file, directory, or URL from the command line. This is really handy when you’re writing a program, because these are easy to invoke from almost any language. You can then pass it a filename (to open that file using the default application for that file type), a directory name to start navigating in that directory (use “.” for the current directory), or a URL like “https://dwheeler.com” to open a browser at that URL.

Here’s how to open files or URLs from the command line, on lots of different platforms (Windows, MacOS, Linux/Unix, and Cygwin).

Windows

You want the start command; when running a command line (cmd.exe) or a batch file, use:

  start filename_or_URL

This is a built-in of cmd, so other programs can’t invoke it as “start”, but other programs can invoke it this way:

  cmd /c start filename_or_URL

Note that if it’s a local filename, and it’s executable, start will execute that program, not open a viewer of it. I haven’t found a Windows command that will easily open files but never execute them, unfortunately. This makes start (and explorer) a potential security problem, depending on how it's used, but I haven't found a secure built-in (other than implementing the command yourself).

Many Internet sources recommend using explorer instead, but there are good reasons to not do that. If you invoke explorer directly, it will ignore the user’s selected Internet browser, and will always use Internet Explorer instead. Users presumably made their choice for a reason, so you should respect it. (Indeed, Internet Explorer has a terrible history of vulnerabilities, so forcing its use seems like an bad idea.) One minor positive when using explorer is that if the executable came from the Internet, then you’ll be given a dialogue on whether or not to execute the file. But this isn't very helpful in real life, because users typically ignore these dialogues. Users typically neither understand nor care what these dialogues say, and they see so many such dialogues that they've been trained to answer “okay” to them. Thus, these security dialogues are basically pointless.

Strictly speaking, redirection to other file-opening programs only works from cmd when “command extensions” are enabled, but as of Windows XP these are enabled by default. As usual, run “help start” to learn more about its options. The related Windows commands assoc and ftype are useful for setting the file type (for a given file extension) and the open command (for a given file type).

MacOS X

You want the open command, i.e.:

  open filename_or_URL

(You can use “-a” to force a different application to run.)

Linux/Unix

You want the xdg-open command, i.e.:

  xdg-open filename_or_URL

This isn’t always installed, so make sure the xdg-utils package is installed (the name of the package is xdg-utils on at least Fedora, Debian, and Ubuntu; it may have a different name on some other distributions).

The xdg-open program is just a wrapper that invokes the “real” opening program(s), but you should use xdg-open instead because the “real” program to do this varies widely depending on user preference. This (and similar wrappers) were developed by the Portland project at Freedesktop.org ( here’s a news clip about Portland). The “real” program for GNOME is gnome-open (which may in turn invoke nautilus), for KDE it’s kde-open or kfmclient (which on KDE 4 may in turn invoke dolphin), for XFCE it’s really exo-open, and there are some other programs like mimeopen. (These, in turn, find the right program to use and invoke it). Where appropriate, xdg-open follows the BROWSER convention.

Unfortunately, xdg-open isn't included with stock Solaris. In many cases, the better solution is to download and install xdg-utils, which is reported to work fine on Solaris. But if you must, an alternative is to directly invoke /usr/dt/bin/sdtwebclient on Solaris.

If you know for certain that a user is using a particular user interface, you could call that program (e.g., gnome-open) directly. But that kind of certainty is rare. For example, you may have written a GNOME program, but the user may be using KDE to invoke it; in that case gnome-open is not the right program to use. After all, if the user is using KDE, then it’s the KDE settings that should be used. In general, use xdg-open; you’ll save your sanity and respect your user’s preferences.

Cygwin

A simple approach is the cygstart command, i.e.:

  cygstart filename_or_URL

Note that if it’s a local filename, and it’s executable, opening the file will execute that program. This is the same problem that Windows has, for the same reasons (Cygwin runs on top of Windows, and thus inherits many Windows defects including this one).

Do not use explorer $(cygpath "path" -w) because although that may be faster, it will often choose the wrong application (in particular, it will fail to use the user’s preferred browser).

Note that start does not directly work on the Cygwin mintty command line, but explorer does. (If you use Cygwin, install mintty immediately; it’s wonderful.) You could use cmd /c start... instead, but don’t; on Cygwin you want to use cygstart instead. When you are running mintty, you can press control-left-button, or press right-button and select "open".

I hope that someday the distributed version of Cygwin will support xdg-open, but as of 2010-07-01 it does not. I do know that there is a patch to xdg-open so that it will invoke cygstart if all else fails. Cygwin does include a slightly related package with the name python-xdg, but as of 2012-03-18 the python-xdg package does not include xdg-open, so that does not help.

Making sure it does the right thing (and security issues)

Beware of common gotchas.

First, there is a basic security problem with the easy-to-use tools in Windows. Note that some of the Windows-based commands listed above will execute that file, instead of running a trusted viewer of the file, if it is a local executable file. This is true for Windows’ start and Cygwin’s cygstart in particular. (It may also true of an xdg-open on Cygwin, if any, since it will have to depend on cygstart). I have not, as yet, found any easy way around this on Windows (including Cygwin, which since it runs on Windows inherits the flaws of Windows). This inability to easily open files without executing them is an example of a basic security vulnerability in Windows. This is an especially glaring flaw in Windows because it is so easy to do this securely on everything else. I would love to hear about something better; please email me if you know of a better solution! But do not hold your breath; I've had this request out for years, and no one has pointed me to anything.

Second, make sure that troublesome filenames are handled properly, including filenames with whitespace (including space, tab, newline, and return). In particular, if you’re invoking it from a Bourne shell (like bash), surround the variable reference with double-quotes (as you should with any value that might contain whitespace). In short, do it like this: xdg-open "$filename"

Third, make sure that your invocation isn’t misinterpreted. All of these programs have different (incompatible) option formats; you need to make sure that a pathname isn’t misinterpreted as an option. This is annoying with Windows, because “/” is the leading character for options and a possible beginning of an absolute filename (Unix/Linux/MacOS have more rational approaches; they use “-”, which is trivially prefixed with “./”). In addition, it’s often ambiguous whether or not an argument is a filename or a URL.

There are three basic possibilities: URLs, absolute pathnames (that start from the filesystem root), and relative pathnames (that start from the current directory):

  1. If you’re handing off a URL, just make sure it looks like one: it should start with PROTOCOL:/... where PROTOCOL is an alphanumeric name that begins with a letter (a-z or A-Z). All of these programs presume that if a parameter looks like a URL, it’s a URL (even if it isn’t). Make sure it’s a protocol they can handle; http:, https:, and ftp: are basically universal. In every one I’ve tested, file: is correctly treated as a local filename.
  2. Absolute pathnames on Unix, Linux, and MacOS are easy - they always begin with “/”, so just pass them in that way. Absolute pathnames on Windows are more annoying to deal with, because they can look like URLs (e.g., “c:/hello”) or like option flags (e.g., “/select”). On Windows a possible solution is to use the “file:” prefix, which will force the string to be interpreted as a file. If you convert a filename to a file: URL, make sure you convert all “%” characters to “%25”, or it will be misinterpreted.
  3. If it’s a relative pathname, make sure it does not look like anything else. In particular, make sure it does not look like a URL or an option. When in doubt, prefix any relative pathname with “./” to make sure it is interpreted correctly. In particular, if the relative pathname begins with “-”, prefix it with “./”; that is especially important on Unix/Linux/MacOS, but it’s even relevant for Windows (many Windows programs also use “-” as the option prefix).

As noted above, if you convert a pathname to a file: URL, make sure you convert all “%” characters to “%25”, or it will be misinterpreted.

Finally, beware of just arbitrarily accepting opening a file; opening /dev/zero (on Unix/Linux) or COM1: (on Windows) can cause trouble. In many circumstances this is not a big deal (if the user can just shut down the hung process), but in a few cases it can cause more serious problems. It’s best if you do not run these with root/admin privileges, because an attacker can then cause more trouble if they can get an arbitrary filename viewed.

And with that, there you go, a simple way to open up files, directories, and URLs.

A simple script

If you do not use Windows, or can trust the files that you open and/or execute, here's a simple shell script to figure out how to invoke the current user's browser. Remember: Don't do this on Windows if you can't trust the file. There's a program called "open" on some systems that is completely different, so we'll try that command only if others do not work out:

#!/bin/sh
# ...
# Figure out how to invoke the current user's browser.
# See: https://dwheeler.com/essays/open-files-urls.html
viewer=FAIL
for possibility in xdg-open gnome-open cygstart start open ; do
  if command -v "$possibility" >/dev/null 2>&1 ; then
    viewer="$possibility"
    break
  fi
done
if [ "$viewer" = FAIL ] ; then
  echo 'No viewer found.' >&2
  exit 1
fi
# Now $viewer is set, so we can use it.
"$viewer" "$FILE_OR_URL_TO_VIEW"

Credits

I found some of this information in How-To Geek’s “Open a File Browser From Your Current Command Prompt/Terminal Directory” and Linux equivalent command for “open” command on Mac/Windows?, but nothing in one place.


Feel free to see my home page at https://dwheeler.com. You may also want to look at my paper Why OSS/FS? Look at the Numbers! and my book on how to develop secure programs.

(C) Copyright 2010 David A. Wheeler.