[HN Gopher] Scriptisto: "Shebang interpreter" that enables writi...
       ___________________________________________________________________
        
       Scriptisto: "Shebang interpreter" that enables writing scripts in
       compiled langs
        
       Author : ronjouch
       Score  : 43 points
       Date   : 2024-02-06 10:41 UTC (1 days ago)
        
 (HTM) web link (github.com)
 (TXT) w3m dump (github.com)
        
       | ronjouch wrote:
       | Via Simon Willison's excellent blog:
       | https://simonwillison.net/2024/Feb/6/scriptisto/ , via lobste.rs:
       | https://lobste.rs/s/ccssqq/scriptisto_writing_one_file_scrip...
        
       | UncleOxidant wrote:
       | It looks like it invokes the compiler every time the script is
       | run? That's nice if you've changed the file, but takes extra time
       | if you haven't. It seems neat at first, but I guess I don't see
       | the advantage over just compiling to an executable and then
       | running that.
        
         | ComputerGuru wrote:
         | I don't want to spam the link, but I actually _just_ posted a
         | top-level comment to a version of this I published back in 2020
         | that does caching and cache invalidation, using the hash of the
         | script as the key for the compiled output path.
         | 
         | EDIT:
         | 
         | Actually, that was how the original version worked, but it had
         | the limitation that once the script changed you could no longer
         | determine the path to the _previous_ executable output to
         | delete, so you could end up accumulating a lot of defunct
         | binaries. Now the hash is stored alongside the target.
        
         | actinium226 wrote:
         | There was some mention in the wiki about caching the result and
         | rebuilding it on change, so it seems well thought out from that
         | perspective.
        
         | catketch wrote:
         | it does some dependency checking, so no compiler invocation if
         | the source isn't changed, the binary is cached
        
       | ComputerGuru wrote:
       | For the rustaceans in the crowd:
       | 
       | It's not a universal "for all compiled langs," but I published a
       | two-liner [0] with zero (non-standard) dependencies or pre-
       | requisites that can be copy-and-pasted to the top of any rust
       | code to turn it into an executable script (cached! also correctly
       | cache-invalidating!) back in 2020.
       | 
       | It even lets you optionally omit the `fn main() { ... }`
       | surrounding your code as well, if you _really_ want to feel like
       | you 're just shell scripting <insert appropriate emoji here>.
       | 
       | It's an example of "polyglot source code" that is valid under two
       | languages at once (in this case, standard sh and rust), (ab)using
       | the rust `#[allow(...)]` "macro" to do double-duty as a shell
       | script comment opener.
       | 
       | [0] https://neosmart.net/blog/self-compiling-rust-code/
        
         | qznc wrote:
         | Nice hack! Would it have been possible back then to use cargo
         | to pull in some dependencies?
         | 
         | The clean solution of cargo script is here:
         | https://github.com/rust-lang/cargo/issues/12207
         | 
         | Following the links, the RFC contains a nice list of similar
         | tools: https://rust-lang.github.io/rfcs/3424-cargo-
         | script.html#prio...
        
           | ComputerGuru wrote:
           | Thanks!
           | 
           | > Would it have been possible back then to use cargo to pull
           | in some dependencies?
           | 
           | Not at the time, at least not that I know of.
           | 
           | I wonder if it's possible to get a link to this solution
           | added to that "prior art" section.
        
       | elitepleb wrote:
       | not too dissimilar an idea from Tom Duff's com executable
       | https://web.archive.org/web/20210204050841/http://www.iq0.co...
        
       | hawski wrote:
       | I prefer to take advantage of the fact that without a proper
       | shebang the file will be first executed by the shell. Then it is
       | easy to do almost whatever you want.
       | 
       | For example I put this in front of my test C files:
       | #if 0       set -e; [ "$0" -nt "$0.bin" ] &&       gcc -Wall
       | -Wextra -pedantic -std=c99 "$0" -o "$0.bin"       exec "$0.bin"
       | "$@"       #endif
       | 
       | I call those: polyglot shell scripts. All my examples are valid
       | files for the language while working as shell scripts at the same
       | time.
       | 
       | In the past when Python 3 was still not obviously there and under
       | different names it was once useful for me to have this on top of
       | a python script:                 "set" "-e"       "exec" "$(for p
       | in python3.7 python3 python; do which p && break; done)" "$0"
       | "$@"
       | 
       | It works, because Python doesn't care about stray strings.
       | 
       | You can also use the trick with Makefiles, although I never
       | needed to use it:                 #\       set -e       #\
       | exec make -f "$0" "$@"
       | 
       | This is not a useful example, but it works. This works, because
       | make will treat slash followed by a new-line as a comment
       | continuation and bash will ignore it.
        
         | metadat wrote:
         | I appreciate a good hack more than most, but this is the kind
         | of cleverness which makes life hell for anyone else who needs
         | to understand what the fuck is happening and why.
         | 
         | At least with TFAs shebang at the top of the file, it kind of
         | gives a clue. Upon reflection, I don't feel great about either
         | way, haha. Even if it makes sense to me, it'll be a little too
         | sneaky for most.
        
       | lambdaba wrote:
       | Somewhat related: nix-shell supports an additional shebang,
       | allowing summoning of any combination of packages, to be made
       | available inside a script. An example from the docs[1]:
       | #!/usr/bin/env nix-shell       #![allow()] /*       #!nix-shell
       | -i bash -p rustc       rsfile="$(readlink -f $0)"
       | binfile="/tmp/$(basename "$rsfile").bin"       rustc "$rsfile" -o
       | "$binfile" --edition=2021 && exec "$binfile" $@ || exit $?
       | */       fn main() {           for argument in
       | std::env::args().skip(1) {               println!("{}",
       | argument);           };           println!("{}",
       | std::env::var("HOME").expect(""));       }
       | 
       | and another:                 #! /usr/bin/env nix-shell       #!
       | nix-shell -p "haskellPackages.ghcWithPackages (p: with p;
       | [turtle])" -i runghc            {-# LANGUAGE OverloadedStrings
       | #-}            import Turtle            main = echo "Hello
       | world!"
       | 
       | 1. https://nixos.wiki/wiki/Nix-shell_shebang
        
       | 12_throw_away wrote:
       | In my experience, writing small but critical shell-script-style
       | mini-programs in rust can actually be a really good idea. The
       | biggest drawback is, IMO, all the overhead of setting up an
       | entire crate just to compile a tiny script, so I'm really happy
       | to see projects like this (and other tools [1]) for this
       | workflow.
       | 
       | [1] https://rust-lang.github.io/rfcs/3424-cargo-
       | script.html#prio...
        
       | IshKebab wrote:
       | The problem with these systems is third party dependencies and
       | IDE support. You really want to be able to use third party
       | dependencies, and have IDEs know about them.
       | 
       | The only systems I know of that do that properly are Deno and I
       | believe F#, though I haven't tried the latter.
       | 
       | Unfortunately Deno has a stupid issue where `deno run` will check
       | for updates and print a "new version of Deno is available"
       | message which rather sours the otherwise great experience of
       | using it for shell scripting.
        
         | TylerE wrote:
         | This is one of the things that drive me nuts about open source
         | projects. Sane defaults are critical to onboarding. Yet default
         | configs seem to mostly be setup for maximum pedantry.
        
       | foobarqux wrote:
       | For python                   #!/usr/bin/env -S
       | PIP_RUN_RETENTION_STRATEGY=persist pip-run              #
       | Requirements:         # pendulum>=1.0.0         # requests
       | import requests         print('hello')
        
       | mirekrusin wrote:
       | Executable, single files with dependency specification should
       | have first class support in all languages.
       | 
       | But that's not going to happen.
       | 
       | So next best option is probably weirdly a markdown file executor
       | which runs triple quoted blocks.
       | 
       | The upside is that you could mix different languages, which is
       | interesting.
        
       ___________________________________________________________________
       (page generated 2024-02-07 23:00 UTC)