[macos] How to run a shell script in OS X by double-clicking?

As of OSX 10.10 (Yosemite) and since at least OS X 10.8 (Mountain Lion), the behavior is as follows when you open (double-click) executable scripts from Finder:

  • Executable scripts[1] with either NO suffix or suffix .command:
  • are executed by default - no setup required:
    • a new Terminal window opens in which the script runs.
    • by default, the window will remain open after the script terminates so you can inspect the output (though at that point the shell that ran the script has exited and you cannot interact with it any longer).
      However, via Terminal's Preferences... > Profiles you can opt to automatically close the window when the script exits.
  • Caveat: the working folder is invariably the current user's home folder, NOT the folder in which the script is located.
    • To make a shell script change to the folder in which it is located, place
      • cd -- "$(dirname "$BASH_SOURCE")" right after the shebang line
      • or, if you must remain POSIX-compliant, cd -- "$(dirname "$0")".
      • For edge cases, such as finding a symlinked script's true source directory, see this answer.
  • If the script is unexpectedly not executable:
    • Make it executable by running chmod +x <script> in Terminal; otherwise, you'll see the following symptoms:
    • .command: Finder displays a misleading error message that suggests the problem can be fixed via File > Get Info, which is not true - use the chmod +x method suggested above.
    • no suffix:
      • with a shebang line (e.g., #!/bin/bash): behavior is as if the suffix were .sh - see below.
      • with no shebang line: opens in your default text editor (which is TextEdit by default).
  • Scripts with suffix .sh, whether executable or not:
  • are opened for editing in TextEdit.app or, if installed, with Xcode.app.
  • Scripts with suffix .scpt or .applescript (even if they're themselves marked as executable, which is not normally the case):
    • opened for editing in [Apple]Script Editor
    • Note that the JXA source-code files seem to have no distinct suffix (yet).
  • Scripts with a custom suffix (a suffix not yet known to the system), whether executable or not (in fact, applies to any kind of file):
    • prompt you for the app to open them with when you first open them, and remember that choice.

[1] Executable means: a script with the executable permission bit(s) set and the calling user - relative to the ownership to the file - therefore potentially being allowed to execute it.
If you use chmod a+x to set all permission bits (which is typical), anyone can invoke it (assuming they're also allowed to read the file based on the read permission bit(s) and the file's ownership).

Examples related to macos

Problems with installation of Google App Engine SDK for php in OS X dyld: Library not loaded: /usr/local/opt/openssl/lib/libssl.1.0.0.dylib dyld: Library not loaded: /usr/local/opt/icu4c/lib/libicui18n.62.dylib error running php after installing node with brew on Mac Could not install packages due to an EnvironmentError: [Errno 13] How do I install Java on Mac OSX allowing version switching? Git is not working after macOS Update (xcrun: error: invalid active developer path (/Library/Developer/CommandLineTools) Can't compile C program on a Mac after upgrade to Mojave You don't have write permissions for the /Library/Ruby/Gems/2.3.0 directory. (mac user) How can I install a previous version of Python 3 in macOS using homebrew? Could not install packages due to a "Environment error :[error 13]: permission denied : 'usr/local/bin/f2py'"

Examples related to shell

Comparing a variable with a string python not working when redirecting from bash script Get first line of a shell command's output How to run shell script file using nodejs? Run bash command on jenkins pipeline Way to create multiline comments in Bash? How to do multiline shell script in Ansible How to check if a file exists in a shell script How to check if an environment variable exists and get its value? Curl to return http status code along with the response docker entrypoint running bash script gets "permission denied"

Examples related to scripting

What does `set -x` do? Creating an array from a text file in Bash Windows batch - concatenate multiple text files into one Raise error in a Bash script How do I assign a null value to a variable in PowerShell? Difference between ${} and $() in Bash Using a batch to copy from network drive to C: or D: drive Check if a string matches a regex in Bash script How to run a script at a certain time on Linux? How to make an "alias" for a long path?

Examples related to desktop

How to center a component in Material-UI and make it responsive? Open a link in browser with java button? How to run a shell script in OS X by double-clicking? Which icon sizes should my Windows application's icon include? Chrome desktop notification example What's the environment variable for the path to the desktop? Good Free Alternative To MS Access