What It Does
When you save a file that starts with #! (a shebang), this extension
automatically makes it executable (similar to chmod +x). No more manually
making your shell scripts, Python scripts, or other executable files runnable.
It is similar in behavior to Emacs'
executable-make-buffer-file-executable-if-script-p when set up as an
after-save hook.
Installation
Install from the VSCode Marketplace, OpenVSX, or
via the command line:
code --install-extension jimeh.executable-on-save
How It Works
The extension watches for file saves. When a file is saved:
- Checks if the first two characters are
#!
- Checks if the file is already executable
- If not executable and has a shebang, applies the appropriate permissions
Behavior Notes
- Only processes files with
file:// URIs (ignores untitled documents)
- Ignores non-file URI schemes (e.g.,
git:)
- Skips files that are already executable
- Requires the shebang at the very beginning of the file (no leading whitespace)
- Only reads the first two characters out of documents for shebang detection
- Shows a small notice when file permissions are modified, which can be silenced
- Runs after every save with very minimal performance impact
Configuration
Enable/Disable
Control whether the extension runs when saving a file:
{
"executableOnSave.enabled": true
}
Default: true
Permission Strategy
Choose how the execute permissions are added:
{
"executableOnSave.permissionStrategy": "umask"
}
Options:
"umask" (default): Respects system umask when adding execute
"read-based": Adds execute only where read permission exists
"all": Adds execute for user, group, and other unconditionally
Umask Strategy (Recommended)
Respects your system's umask setting, following Unix conventions. Only adds
execute permissions that would be allowed on newly created files.
With umask 0o022 (typical):
| Before |
After |
Description |
rw-r--r-- |
rwxr-xr-x |
All get execute |
rw------- |
rwx--x--x |
All get execute |
rw-rw-r-- |
rwxrwxr-x |
All get execute |
With umask 0o077 (restrictive):
| Before |
After |
Description |
rw-r--r-- |
rwxr--r-- |
Only user gets execute |
rw------- |
rwx------ |
Only user gets execute |
rw-rw-r-- |
rwxrw-r-- |
Only user gets execute |
Technical: Calculates default file permissions (0o777 & ~umask), extracts
execute bits, and applies them via bitwise OR.
Read-based Strategy
Maintains permission symmetry by only adding execute where read exists:
| Before |
After |
Description |
rw-r--r-- |
rwxr-xr-x |
Standard file permissions |
rw------- |
rwx------ |
Private file stays private |
rw-r----- |
rwxr-x--- |
Group-readable becomes group-executable |
Technical: shifts read bits right by 2 positions to derive execute bits.
All Strategy
Always adds execute for all three permission groups:
| Before |
After |
Description |
rw-r--r-- |
rwxr-xr-x |
Standard file permissions |
rw------- |
rwx--x--x |
Adds execute for user, group, and other |
rw-r----- |
rwxr-x--x |
Adds execute for user, group, and other |
Technical: performs bitwise OR with 0o111.
Silent Mode
Disable information popups when permissions change:
{
"executableOnSave.silent": false
}
Set to true to suppress notifications altogether.
Manual Execution
Run "Make Executable If Script" from the command palette to manually run checks
and mark the current file as executable if needed.
- macOS: Full support
- Linux: Full support
- BSD: Full support
- Windows: Disabled (Windows uses different permission model)
License
MIT