elves / elvish

Powerful scripting language & versatile interactive shell
https://elv.sh/
BSD 2-Clause "Simplified" License
5.53k stars 297 forks source link

Support Shebang? #1709

Closed da-liii closed 12 months ago

da-liii commented 12 months ago

https://en.wikipedia.org/wiki/Shebang_(Unix)

nichtsundniemand commented 12 months ago

Could you please elaborate a bit?

What works? What doesn't work?

krader1961 commented 12 months ago

@darcy-shen, Elvish code works fine when put in a file that begins with a shebang line. I have several Elvish programs where I use that mechanism to make the Elvish program work like any other command I might run. Did you try this and run into a problem?

Note that shebang lines don't work on Windows unless you use a shell like Cygwin Bash which emulate the Unix behavior.

P.S., When opening an issue of this type you should always include the Elvish version you are using and the platform you are using.

da-liii commented 12 months ago

Note that shebang lines don't work on Windows unless you use a shell like Cygwin Bash which emulate the Unix behavior.

You read my mind. Elvish already supports shebang. I was using Windows, and I thought Elvish does not support Shebang. Finally I found that I was wrong.

jcrben commented 3 months ago

The question that comes to mind: why not support the shebang on Windows similar to the way cygwin Bash does? Shoot for a simpler glide path. @xiaq

On Windows the concept of chmod +x <file> is lacking, so basically cygwin / msys bash checks the first line of a file and if it's a shebang it'll treat it as an executable.

image

~\dotfiles> cat ./something
#!/usr/bin/env bash
echo "yoyoyo"
~\dotfiles> ./something
Exception: exec: "./something": executable file not found in %PATH%
  [tty 9]:1:1-11: ./something
xiaq commented 3 months ago

@jcrben That's a nice idea. However, shebang lines like #!/usr/bin/env bash only works on Cygwin because it emulates Unix filesystem paths, which Elvish doesn't do (it uses normal Windows APIs).

So for Elvish to support shebangs on Windows one would have to write:

#!C:\Cygwin\bin\bash
...

Which means that

So the benefit is quite limited. The standard approach on Windows to write executable scripts is to write a thin .bat wrapper for the actual script and it works in any shell.

jcrben commented 3 months ago

@xiaq thanks for those insights, makes sense

Another way to consider it tho: people using Cygwin are looking for Linux emulation. So if elvish could handle shebang when people enter it from a cygwin environment (as I'm doing in my screenshot above) that would alleviate those concerns

I'm pretty much exclusively using Windows from cygwin (actually msys2 bash but same difference) except when I need to test running something outside it

xiaq commented 3 months ago

@jcrben Right, if Elvish has access to Cygwin's virtual filesystem this would make a ton of sense. I don't think this is technically feasible though: the way Cygwin works is that it provides a dynamically linked library (cygwin1.dll) that programs link to, which provides a POSIX C API and implements the virtual filesystem stuff (among others). This library replaces libc which is why many Unix programs can be ported directly (with re-compilation, but no to little code change).

Go's standard library in general does not actually depend on libc (it uses syscalls directly), so Elvish can't be "Cygwinized" in the same way that, say bash, is "Cygwinized". It is technically possible for Elvish to explicitly depend on cygwin1.dll and use it to access Cygwin's virtual filesystem but it's going to be a lot of extra work.

krader1961 commented 3 months ago

For those who might be wondering why this issue exists.... The kernel code on Unix like OS's that creates new processes, given a path to a file (the exec family of functions), opens the file and looks for the magic #! sequence at the start of the file to determine if it should invoke an interpreter to handle the program. See https://en.wikipedia.org/wiki/Shebang_(Unix). My first introduction to this feature was Sequent's DYNIX/3 OS in the mid 1980's that was based on 4.2BSD. Windows does not have an equivalent mechanism in its OS kernel. Windows primarily relies on file extensions to determine how to execute a program.

Linking against the Cygwin/MSYS2 libc DLL is certain to be far too expensive and fragile to be practical. However, it seems to me Cygwin's VFS mapping logic is stable enough it should be possible to implement it in a modest amount of Go code that won't need frequent updating. I briefly looked into doing so a few years ago when I setup my first Windows/MSYS2 environment for doing Elvish builds and running its unit tests on Windows. I quickly abandoned the effort because I only use Windows for testing software, like Elvish, on Windows. In other words I don't use Windows on a daily basis and thus lack sufficient motivation to improve matters. Still, someone with sufficient motivation could probably write the Cygwin VFS logic in Go with a modest amount of effort. Most of the work would involve integrating that logic into the Elvish code in a manner that did not affect its behavior on Unix systems.

As with switching from the legacy BoltDB interactive history to a simpler flat-file history without the need for a daemon process (see issue #1222) it's just a small matter of someone with sufficient motivation to put forth the effort to write the necessary code. 😺

da-liii commented 3 months ago

I'm using an extra bat script on windows as a solution.

For example, here is the content of format.bat

elvish format

It will execute the format elvish scripting file.

Thanks to the fix of https://github.com/elves/elvish/issues/1746

The solution works fine in elvish 0.20.x.