{"id":22367641,"url":"https://github.com/hugojosefson/deno-shebang","last_synced_at":"2025-07-30T17:33:01.367Z","repository":{"id":63301262,"uuid":"348447012","full_name":"hugojosefson/deno-shebang","owner":"hugojosefson","description":"Make .ts / .js files TRULY standalone self-executable.","archived":false,"fork":false,"pushed_at":"2024-04-01T19:57:37.000Z","size":115,"stargazers_count":9,"open_issues_count":1,"forks_count":0,"subscribers_count":3,"default_branch":"main","last_synced_at":"2024-09-17T01:27:45.429Z","etag":null,"topics":["bash","deno","executable","hashbang","posix","script","sh","shebang","shell"],"latest_commit_sha":null,"homepage":"","language":"Shell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"cc0-1.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/hugojosefson.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null}},"created_at":"2021-03-16T18:08:45.000Z","updated_at":"2024-04-01T19:59:04.000Z","dependencies_parsed_at":"2024-03-31T22:26:54.445Z","dependency_job_id":"a66cb818-891c-4668-8cbb-aed76afdba1b","html_url":"https://github.com/hugojosefson/deno-shebang","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hugojosefson%2Fdeno-shebang","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hugojosefson%2Fdeno-shebang/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hugojosefson%2Fdeno-shebang/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hugojosefson%2Fdeno-shebang/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/hugojosefson","download_url":"https://codeload.github.com/hugojosefson/deno-shebang/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":228165050,"owners_count":17879185,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["bash","deno","executable","hashbang","posix","script","sh","shebang","shell"],"created_at":"2024-12-04T18:19:46.746Z","updated_at":"2024-12-04T18:19:47.251Z","avatar_url":"https://github.com/hugojosefson.png","language":"Shell","funding_links":[],"categories":[],"sub_categories":[],"readme":"# deno-shebang\n\nMake TypeScript/JavaScript files truly standalone self-executable.\n\n## What?!\n\nPut this two line [shebang](https://en.wikipedia.org/wiki/Shebang_(Unix)) header\nin a Deno-compatible `.ts` or `.js` file, to make it standalone self-executable:\n\n```typescript\n#!/bin/sh\n// 2\u003e/dev/null;DENO_VERSION_RANGE=\"^1.42.0\";DENO_RUN_ARGS=\"\";set -e;V=\"$DENO_VERSION_RANGE\";A=\"$DENO_RUN_ARGS\";h(){ [ -x \"$(command -v \"$1\" 2\u003e\u00261)\" ];};g(){ u=\"$([ \"$(id -u)\" != 0 ]\u0026\u0026echo sudo||:)\";if h brew;then echo \"brew install $1\";elif h apt;then echo \"($u apt update \u0026\u0026 $u DEBIAN_FRONTEND=noninteractive apt install -y $1)\";elif h yum;then echo \"$u yum install -y $1\";elif h pacman;then echo \"$u pacman -yS --noconfirm $1\";elif h opkg-install;then echo \"$u opkg-install $1\";fi;};p(){ q=\"$(g \"$1\")\";if [ -z \"$q\" ];then echo \"Please install '$1' manually, then try again.\"\u003e\u00262;exit 1;fi;eval \"o=\\\"\\$(set +o)\\\";set -x;$q;set +x;eval \\\"\\$o\\\"\"\u003e\u00262;};f(){ h \"$1\"||p \"$1\";};w(){ [ -n \"$1\" ] \u0026\u0026 \"$1\" -V \u003e/dev/null 2\u003e\u00261;};U=\"$(l=$(printf \"%s\" \"$V\"|wc -c);for i in $(seq 1 $l);do c=$(printf \"%s\" \"$V\"|cut -c $i);printf '%%%02X' \"'$c\";done)\";D=\"$(w \"$(command -v deno||:)\"||:)\";t(){ i=\"$(if h findmnt;then findmnt -Ononoexec,noro -ttmpfs -nboAVAIL,TARGET|sort -rn|while IFS=$'\\n\\t ' read -r a m;do [ \"$a\" -ge 150000000 ]\u0026\u0026[ -d \"$m\" ]\u0026\u0026printf %s \"$m\"\u0026\u0026break||:;done;fi)\";printf %s \"${i:-\"${TMPDIR:-/tmp}\"}\";};s(){ deno eval \"import{satisfies as e}from'https://deno.land/x/semver@v1.4.1/mod.ts';Deno.exit(e(Deno.version.deno,'$V')?0:1);\"\u003e/dev/null 2\u003e\u00261;};e(){ R=\"$(t)/deno-range-$V/bin\";mkdir -p \"$R\";export PATH=\"$R:$PATH\";s\u0026\u0026return;f curl;v=\"$(curl -sSfL \"https://semver-version.deno.dev/api/github/denoland/deno/$U\")\";i=\"$(t)/deno-$v\";ln -sf \"$i/bin/deno\" \"$R/deno\";s \u0026\u0026 return;f unzip;([ \"${A#*-q}\" != \"$A\" ]\u0026\u0026exec 2\u003e/dev/null;curl -fsSL https://deno.land/install.sh|DENO_INSTALL=\"$i\" sh -s $DENO_INSTALL_ARGS \"$v\"|grep -iv discord\u003e\u00262);};e;exec deno run $A \"$0\" \"$@\"\n```\n\nIt automatically downloads a correct version of the single\n[deno](https://deno.land/) executable if needed, to a temp directory, and runs\nthe script directly using that.\n\nHowever, if it finds `deno` already installed, and its version is satisfactory,\nit uses that instead **without downloading deno at all**. For example from a\nprevious run, or from an otherwise installed `deno` by the user.\n\n## Requirements\n\nThese are the only things you need, to run a script that has this shebang:\n\n- `/bin/sh` a.k.a. Bourne shell, POSIX shell\n- `curl`\n- `unzip`\n\nAs you can see, ~~deno~~ needs NOT be installed.\n\n## How to use\n\n### Step 1: Copy-paste shebang file header\n\nCopy/paste this two-liner, into the beginning of your TypeScript file:\n\n```typescript\n#!/bin/sh\n// 2\u003e/dev/null;DENO_VERSION_RANGE=\"^1.42.0\";DENO_RUN_ARGS=\"\";set -e;V=\"$DENO_VERSION_RANGE\";A=\"$DENO_RUN_ARGS\";h(){ [ -x \"$(command -v \"$1\" 2\u003e\u00261)\" ];};g(){ u=\"$([ \"$(id -u)\" != 0 ]\u0026\u0026echo sudo||:)\";if h brew;then echo \"brew install $1\";elif h apt;then echo \"($u apt update \u0026\u0026 $u DEBIAN_FRONTEND=noninteractive apt install -y $1)\";elif h yum;then echo \"$u yum install -y $1\";elif h pacman;then echo \"$u pacman -yS --noconfirm $1\";elif h opkg-install;then echo \"$u opkg-install $1\";fi;};p(){ q=\"$(g \"$1\")\";if [ -z \"$q\" ];then echo \"Please install '$1' manually, then try again.\"\u003e\u00262;exit 1;fi;eval \"o=\\\"\\$(set +o)\\\";set -x;$q;set +x;eval \\\"\\$o\\\"\"\u003e\u00262;};f(){ h \"$1\"||p \"$1\";};w(){ [ -n \"$1\" ] \u0026\u0026 \"$1\" -V \u003e/dev/null 2\u003e\u00261;};U=\"$(l=$(printf \"%s\" \"$V\"|wc -c);for i in $(seq 1 $l);do c=$(printf \"%s\" \"$V\"|cut -c $i);printf '%%%02X' \"'$c\";done)\";D=\"$(w \"$(command -v deno||:)\"||:)\";t(){ i=\"$(if h findmnt;then findmnt -Ononoexec,noro -ttmpfs -nboAVAIL,TARGET|sort -rn|while IFS=$'\\n\\t ' read -r a m;do [ \"$a\" -ge 150000000 ]\u0026\u0026[ -d \"$m\" ]\u0026\u0026printf %s \"$m\"\u0026\u0026break||:;done;fi)\";printf %s \"${i:-\"${TMPDIR:-/tmp}\"}\";};s(){ deno eval \"import{satisfies as e}from'https://deno.land/x/semver@v1.4.1/mod.ts';Deno.exit(e(Deno.version.deno,'$V')?0:1);\"\u003e/dev/null 2\u003e\u00261;};e(){ R=\"$(t)/deno-range-$V/bin\";mkdir -p \"$R\";export PATH=\"$R:$PATH\";s\u0026\u0026return;f curl;v=\"$(curl -sSfL \"https://semver-version.deno.dev/api/github/denoland/deno/$U\")\";i=\"$(t)/deno-$v\";ln -sf \"$i/bin/deno\" \"$R/deno\";s \u0026\u0026 return;f unzip;([ \"${A#*-q}\" != \"$A\" ]\u0026\u0026exec 2\u003e/dev/null;curl -fsSL https://deno.land/install.sh|DENO_INSTALL=\"$i\" sh -s $DENO_INSTALL_ARGS \"$v\"|grep -iv discord\u003e\u00262);};e;exec deno run $A \"$0\" \"$@\"\n```\n\n### Step 2: `chmod` it\n\nSet the executable flag on the file:\n\n```sh\nchmod +x myscript.ts\n```\n\n### Step 3: Run it!\n\n```sh\n./myscript.ts\n```\n\nAt this point, it doesn't even need to be named `.ts`. You can remove the\nextension, or name it something else.\n\n## Configuration\n\nIn `DENO_VERSION_RANGE`, you can change to whatever\n[Semantic Versioning range](https://devhints.io/semver) of the\n[Deno releases](https://github.com/denoland/deno/releases) your script expects.\n\nIn `DENO_RUN_ARGS`, you may set any additional arguments to `deno run`, such as\n`--allow-read=. --allow-network`.\n\n## Features\n\n### Read from stdin\n\nYour script can read from `stdin`, and it will work fine.\n\nFor example:\n\n```sh\ncat inputfile.txt | ./myscript.ts\n```\n\n### Arguments\n\nYour script is free to access command-line arguments.\n\n```sh\n./myscript.ts --help\n./myscript.ts -i inputfile.txt -o outputfile.txt\n```\n\n### curl | sh\n\nThere is an extended variant of this shebang, which will also let you pipe your\nscript into `sh`:\n\n```typescript\n#!/bin/sh\n// 2\u003e/dev/null;DENO_VERSION_RANGE=\"^1.42.0\";DENO_RUN_ARGS=\"\";set -e;V=\"$DENO_VERSION_RANGE\";A=\"$DENO_RUN_ARGS\";h(){ [ -x \"$(command -v \"$1\" 2\u003e\u00261)\" ];};g(){ u=\"$([ \"$(id -u)\" != 0 ]\u0026\u0026echo sudo||:)\";if h brew;then echo \"brew install $1\";elif h apt;then echo \"($u apt update \u0026\u0026 $u DEBIAN_FRONTEND=noninteractive apt install -y $1)\";elif h yum;then echo \"$u yum install -y $1\";elif h pacman;then echo \"$u pacman -yS --noconfirm $1\";elif h opkg-install;then echo \"$u opkg-install $1\";fi;};p(){ q=\"$(g \"$1\")\";if [ -z \"$q\" ];then echo \"Please install '$1' manually, then try again.\"\u003e\u00262;exit 1;fi;eval \"o=\\\"\\$(set +o)\\\";set -x;$q;set +x;eval \\\"\\$o\\\"\"\u003e\u00262;};f(){ h \"$1\"||p \"$1\";};w(){ [ -n \"$1\" ] \u0026\u0026 \"$1\" -V \u003e/dev/null 2\u003e\u00261;};U=\"$(l=$(printf \"%s\" \"$V\"|wc -c);for i in $(seq 1 $l);do c=$(printf \"%s\" \"$V\"|cut -c $i);printf '%%%02X' \"'$c\";done)\";D=\"$(w \"$(command -v deno||:)\"||:)\";t(){ i=\"$(if h findmnt;then findmnt -Ononoexec,noro -ttmpfs -nboAVAIL,TARGET|sort -rn|while IFS=$'\\n\\t ' read -r a m;do [ \"$a\" -ge 150000000 ]\u0026\u0026[ -d \"$m\" ]\u0026\u0026printf %s \"$m\"\u0026\u0026break||:;done;fi)\";printf %s \"${i:-\"${TMPDIR:-/tmp}\"}\";};z(){ m=\"$(command -v \"$0\"||true)\";l=\"/* 2\u003e/dev/null\";! [ -z \"$m\" ]\u0026\u0026[ -r \"$m\" ]\u0026\u0026[ \"$(head -c3 \"$m\")\" = '#!/' ]\u0026\u0026(read x \u0026\u0026 read y \u0026\u0026[ \"$x\" = \"#!/bin/sh\" ]\u0026\u0026[ \"$l\" != \"${y%\"$l\"*}\" ])\u003c\"$m\";};s(){ deno eval \"import{satisfies as e}from'https://deno.land/x/semver@v1.4.1/mod.ts';Deno.exit(e(Deno.version.deno,'$V')?0:1);\"\u003e/dev/null 2\u003e\u00261;};e(){ R=\"$(t)/deno-range-$V/bin\";mkdir -p \"$R\";export PATH=\"$R:$PATH\";s\u0026\u0026return;f curl;v=\"$(curl -sSfL \"https://semver-version.deno.dev/api/github/denoland/deno/$U\")\";i=\"$(t)/deno-$v\";ln -sf \"$i/bin/deno\" \"$R/deno\";s \u0026\u0026 return;f unzip;([ \"${A#*-q}\" != \"$A\" ]\u0026\u0026exec 2\u003e/dev/null;curl -fsSL https://deno.land/install.sh|DENO_INSTALL=\"$i\" sh -s $DENO_INSTALL_ARGS \"$v\"|grep -iv discord\u003e\u00262);};e;z\u0026\u0026exec deno run $A \"$0\" \"$@\";exec deno run $A - \"$@\"\u003c\u003c'//🔚'\n```\n\nUsing this, you can run both run the script normally from a file, or directly\nfrom the internet using `curl` and `sh`:\n\n```sh\ncurl -s https://example.com/myscript.ts | sh\n```\n\nHowever, piping the script into `sh`, you can no longer read from `stdin` like\nabove. That's because `deno` will be reading the script from `stdin` instead.\n\n### curl | sh + arguments\n\nWhen piping the script through `sh`, you can still use command-line arguments.\nYou just have to prefix them to `sh` with `-s --` like this:\n\n```sh\ncurl -s https://example.com/myscript.ts | sh -s -- -i inputfile.txt -o outputfile.txt\n```\n\n## Full source code\n\nYou can view the full un-minified source code in:\n\n- [src/deno-shebang.sh](src/deno-shebang.sh)\n- [src/deno-shebang-piped.sh](src/deno-shebang-piped.sh)\n\n## Complete examples\n\n- [example.ts](example.ts)\n- [example.min.ts](example.min.ts)\n- [example-piped.ts](example-piped.ts)\n- [example-piped.min.ts](example-piped.min.ts)\n\n## License\n\nCC0-1.0\n\n\u003cp xmlns:cc=\"http://creativecommons.org/ns#\" xmlns:dct=\"http://purl.org/dc/terms/\"\u003e\u003ca property=\"dct:title\" rel=\"cc:attributionURL\" href=\"https://github.com/hugojosefson/deno-shebang\"\u003edeno-shebang\u003c/a\u003e by \u003ca rel=\"cc:attributionURL dct:creator\" property=\"cc:attributionName\" href=\"https://www.hugojosefson.com\"\u003eHugo Josefson\u003c/a\u003e is marked with \u003ca href=\"http://creativecommons.org/publicdomain/zero/1.0?ref=chooser-v1\" target=\"_blank\" rel=\"license noopener noreferrer\" style=\"display:inline-block;\"\u003eCC0 1.0\u003cimg style=\"height:22px!important;margin-left:3px;vertical-align:text-bottom;\" src=\"https://mirrors.creativecommons.org/presskit/icons/cc.svg?ref=chooser-v1\"\u003e\u003cimg style=\"height:22px!important;margin-left:3px;vertical-align:text-bottom;\" src=\"https://mirrors.creativecommons.org/presskit/icons/zero.svg?ref=chooser-v1\"\u003e\u003c/a\u003e\u003c/p\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhugojosefson%2Fdeno-shebang","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhugojosefson%2Fdeno-shebang","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhugojosefson%2Fdeno-shebang/lists"}