13

I have F# 2.0 installed with Mono, and I'd like to ./ my F# scripts. Which shebang line should I use for Mac OS X? Can this shebang line be generalized for Mac OS X and Linux?

mcandre
  • 22,868
  • 20
  • 88
  • 147
  • I think this may be problematic as `#`is not a comment in F# - you may be better writing a simple bash script. If you are talking about compiled scripts, for linux there is a kernel patch to make `./` work - not sure about for mac – John Palmer Nov 10 '12 at 05:47
  • 2
    @JohnPalmer Yes, the lack of `#` comments in F# and other languages makes shebangs more difficult, though not impossible. http://rosettacode.org/wiki/Multiline_shebang – mcandre Nov 10 '12 at 06:01
  • that is quite neat - you could hide an entire bash script there which could allow you to do portability stuff – John Palmer Nov 10 '12 at 06:40
  • This is a very neat trick @mcandre--thanks for sharing it. – Onorio Catenacci Nov 12 '12 at 15:46

3 Answers3

8

NOTE fsharpi has been superseded by dotnet fsi. See this answer.


In Mac OS X, the program is fsharpi.

hello.fs:

#light (*
    exec fsharpi --exec $0 --quiet
*)

System.Console.WriteLine "Hello World"
Sridhar Ratnakumar
  • 81,433
  • 63
  • 146
  • 187
mcandre
  • 22,868
  • 20
  • 88
  • 147
8

So, in @mcandre's answer, it works because most shells revert to bourne shell when they don't find a shebang.

So having #light which is both valid F# and a comment in bourne shell allows each scripting environment to see what it understands.

The script inside however could be improved. When we execute a script adding --quiet to --exec seems redundant, also we expect all arguments to be passed to the script. A more ideal version would be exec fsharpi --exec $0 $* so all arguments would be passed as if you ran the command explicitly.

#light is not the only # preceded directive in F#. Preprocessor defines also would work and could be intuitive to what is going on. Putting a shell script between #if run_with_bin_sh and #endif would be invisible to f# since run_with_bin_sh wouldn't be defined.

Example fsx:

#if run_with_bin_sh 
  exec fsharpi --exec $0 $*
#endif
printfn "%A" fsi.CommandLineArgs

update: Real shebang support such as #!/usr/bin/env fsharpi --exec has been add into the official Microsoft F# code base. So it should work with future versions of F#.

update 2: #!/usr/bin/env fsharpi --exec works great for mac, but not on linux. Linux needs to be #!/usr/bin/fsharpi --exec the incompatibilty is annoying.

If you want a cross platform fsharp shebang. The following will work.

#!/bin/sh
#if run_with_bin_sh
  exec fsharpi --exec $0 $*
#endif
jbtule
  • 31,383
  • 12
  • 95
  • 128
  • 1
    `/bin/usr/env`??? that looks wrong, is that a typo? I guess you meant `/usr/bin/env` – knocte Oct 07 '16 at 08:06
  • 1
    In recent versions you don't need the `--exec` parameter anymore, which means that `#!/usr/bin/env fsharpi` now is a cross-platform shebang line. – Tobia Sep 16 '18 at 18:43
6

With the most recent crossplatform .net installed and the most recent linux (coreutil 8.30 <=) and bsd / mac os releases. You can use the following shebang for F# .fsx scripts.

#!/usr/bin/env -S dotnet fsi
jbtule
  • 31,383
  • 12
  • 95
  • 128