Multiline shebang

From Rosetta Code
Revision as of 23:30, 8 August 2011 by rosettacode>Kernigh (→‎{{header|Ruby}}: Keep ARGV[0] when doing exec "/bin/sh".)
Multiline shebang is a draft programming task. It is not yet considered ready to be promoted as a complete task, for reasons that should be found in its talk page.

Simple shebangs can help with scripting, e.g. #!/usr/bin/env python at the top of a Python script will allow it to be run in a terminal as "./script.py".

Occasionally, a more complex shebang line is needed. For example, some languages do not include the program name in ARGV; a multiline shebang can reorder the arguments so that the program name is included in ARGV.

The syntax for a multiline shebang is complicated. The shebang lines must be simultaneously commented away from the main language and revealed to Bash so that they can be executed.

Clojure

The namespace = basename = filename minus the extension must be passed as a value to Clojure's -m flag.

<lang clojure>":";exec clj -m `basename $0 .clj` $0 ${1+"$@"} ":";exit</lang>

Common Lisp

Here, the script name is passed once to CLISP and once to ext:*args*, which normally omits it.

<lang lisp>#!/bin/bash

  1. |

exec clisp -q -q $0 $0 ${1+"$@"} exit |#</lang>

Emacs Lisp

<lang lisp>:;exec emacs -batch -l $0 -f main $*</lang>

Erlang

This example is incorrect. Please fix the code and remove this message.

Details: This is not a multiline shebang. A plain #! can only have one line.

Note that the binary is escript, not erl. The latter refuses to compile or run code that contains a shebang.

<lang erlang>#!/usr/bin/env escript</lang>

Haskell

This example is incorrect. Please fix the code and remove this message.

Details: This is not a multiline shebang. A plain #! can only have one line.

A plain shebang will do.

<lang haskell>#!/usr/bin/env runhaskell</lang>

JavaScript

Works with: Node.js
This example is incorrect. Please fix the code and remove this message.

Details: This is not a multiline shebang. A plain #! can only have one line.

A plain shebang will do.

<lang javascript>#!/usr/bin/env node</lang>

Lua

This example is incorrect. Please fix the code and remove this message.

Details: This is not a multiline shebang. A plain #! can only have one line.

A plain shebang will do.

<lang lua>#!/usr/bin/env lua</lang>

newLISP

This example is incorrect. Please fix the code and remove this message.

Details: This is not a multiline shebang. A plain #! can only have one line.

A plain shebang will do.

<lang lisp>#!/usr/bin/env newlisp</lang>

Perl

From perldoc perlrun, the following is supposed to find perl one way or another under sh, csh or perl. <lang perl>#!/usr/bin/perl eval '(exit $?0)' && eval 'exec perl -wS $0 ${1+"$@"}' & eval 'exec /usr/bin/perl -wS $0 $argv:q' if $running_under_some_shell;</lang>

Python

This example is incorrect. Please fix the code and remove this message.

Details: This is not a multiline shebang. A plain #! can only have one line.

A plain shebang will do.

<lang python>#!/usr/bin/env python</lang>

R

This example is incorrect. Please fix the code and remove this message.

Details: This is not a multiline shebang. A plain #! can only have one line.

Note that the binary is Rscript, not the R interpreter. Regardless, scripts must end with q("no") in order to terminate and return to the shell.

<lang R>#!/usr/bin/env Rscript</lang>

Ruby

One can use a single-line shebang, like #!/usr/bin/env ruby, and use Kernel#system or `backquotes` to run any extra shell commands. A multi-line shebang is possible, but not necessary.

This script works both ways: either /bin/sh script.rb or ruby script.rb would run multiple lines of shell commands, and then start Ruby.

<lang ruby>#!/bin/sh

  1. Insert shell code here!

printf '%s\n' "Shell running $0" i=1 for arg do

 printf '  %s\n' "\${$i}: $arg"
 i=`expr $i + 1`

done

  1. Switch from shell to Ruby.

exec ${RUBY-ruby} -x "$0" --coming-from-sh "$@"

  1. !ruby

ARGV[0] == "--coming-from-sh" or exec "/bin/sh", $0, *ARGV ARGV.shift

  1. Insert Ruby code here!

puts "Ruby running #$0" ARGV.each_with_index do |arg, i|

 puts "  ARGV[#{i}]: #{arg}"

end</lang>

When running /bin/sh scratch.rb, the shell:

  1. ignores #!/bin/sh, because it is a comment.
  2. runs multiple lines of shell code.
  3. executes ruby -x; user can set RUBY environment variable to pick different Ruby, like RUBY=ruby19 or RUBY=jruby.

ruby -x skips every line until the first Ruby shebang. This line must start with "#!" and must contain "ruby". (So "#!ruby" is the shortest shebang to work.)

When running ruby scratch.rb (without -x option), Ruby notices that the first line "#!/bin/sh" is a foreign shebang.

  • Ruby 1.8 then interprets this shebang and executes /bin/sh.
  • Ruby 1.9 then assumes -x option and skips to the first Ruby shebang. The script is not --coming-from-sh, so it executes /bin/sh.

Scheme

Works with: Chicken Scheme

#| ... |# provides just the right environment for the multiline shebang. Here, the script name is passed once to the Chicken Scheme Interpreter and once to be picked up in args.

<lang scheme>#!/bin/bash

  1. |

exec csi -ss $0 ${1+"$@"} exit |#</lang>

Smalltalk

<lang smalltalk>"exec" "gst" "-f" "$0" "$0" "$@" "exit"</lang>

Tcl

It is normal to use a line like this: <lang tcl>#!/usr/bin/env tclsh</lang> But in cases where that is not enough perhaps because it needs some logic to locate the Tcl interpreter to use the differences in the way Tcl and the Bourne shell interpret end-of-line backslashes in comments can be used: <lang tcl>#!/bin/sh

  1. Next line is comment in Tcl, but not in sh... \

exec tclsh "$0" ${1+"$@"}</lang> Additional complexity can be added so long as the lines for the shell are commented in a Tcl sense.