Skip to content

Instantly share code, notes, and snippets.

@505e06b2
Last active November 29, 2022 22:11
Show Gist options
  • Save 505e06b2/f1141603df8a1ec40974ce8b9609b4d9 to your computer and use it in GitHub Desktop.
Save 505e06b2/f1141603df8a1ec40974ce8b9609b4d9 to your computer and use it in GitHub Desktop.
Shebang proxy, specifically for Windows
#!/usr/bin/env python
import os, sys
import subprocess, shutil, shlex
from pathlib import Path
def getShebangLine(executable_path):
with open(executable_path, "rb") as f:
magic = f.read(2)
if magic != b"#!":
return None
shebang = f.readline()
return shebang.decode("utf8").strip()
def getPathext(additions):
parsed_pathext = (os.environ.get("PATHEXT") or "").split(os.pathsep)
return_value = parsed_pathext + additions
os.environ["PATHEXT"] = f"{os.pathsep}".join(return_value)
return return_value
def findCorrectExtension(parsed_pathext, extensionless_filepath):
for possible_extension in parsed_pathext:
potential_fullpath = Path(extensionless_filepath).with_suffix(possible_extension)
if potential_fullpath.is_file():
return potential_fullpath
return extensionless_filepath
if __name__ == "__main__":
import argparse
parser = argparse.ArgumentParser(description="Parse an execute a shebang line from a script")
parser.add_argument("script_file", type=Path)
parser.add_argument("arguments", type=str, nargs="*")
args = parser.parse_args()
env_pathext = getPathext([".PS1", ".SH"])
executable_path = args.script_file
if str(executable_path) == executable_path.name: #relative paths passed to else
absolute_executable_path = Path(shutil.which(executable_path.name) or executable_path.name)
else:
absolute_executable_path = (executable_path if executable_path.suffix else findCorrectExtension(env_pathext, executable_path)).resolve()
if not absolute_executable_path.is_file():
print(f"Can't find \"{executable_path}\"", file=sys.stderr)
sys.exit(1)
if not os.access(absolute_executable_path, os.X_OK):
print(f"\"{absolute_executable_path}\" is not executable", file=sys.stderr)
sys.exit(1)
shebang = getShebangLine(absolute_executable_path)
if shebang == None:
print(f"\"{absolute_executable_path}\" does not have a shebang line", file=sys.stderr)
sys.exit(1)
parsed_shebang = shlex.split(shebang)
if os.name == "nt" and parsed_shebang[0] == "/usr/bin/env":
parsed_shebang[0] = "env"
subprocess.run(parsed_shebang + [absolute_executable_path] + args.arguments)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment