Multiline shebang: Difference between revisions
(correct jq section) |
|||
(20 intermediate revisions by 10 users not shown) | |||
Line 1: | Line 1: | ||
{{draft task|Basic language learning}} |
{{draft task|Basic language learning}} |
||
Simple shebangs can help with scripting, e.g., <code>#!/usr/bin/env python</code> at the top of a Python script will allow it to be run in a terminal as "<code>./script.py</code>". |
Simple shebangs can help with scripting, e.g., <code>#!/usr/bin/env python</code> at the top of a Python script will allow it to be run in a terminal as "<code>./script.py</code>". |
||
Line 10: | Line 11: | ||
;See also |
;See also |
||
* [[Native shebang]] - where the "program loaded" is ''of'' the actual native task language. |
* [[Native shebang]] - where the "program loaded" is ''of'' the actual native task language. |
||
<br><br> |
|||
=={{header|Ada}}== |
=={{header|Ada}}== |
||
Line 15: | Line 17: | ||
{{trans|C}} |
{{trans|C}} |
||
< |
<syntaxhighlight lang="ada">#!/bin/bash |
||
sed -n -e '7,$p' < "$0" > mulshbang.adb |
sed -n -e '7,$p' < "$0" > mulshbang.adb |
||
gnatmake -q mulshbang |
gnatmake -q mulshbang |
||
Line 31: | Line 33: | ||
Ada.Command_Line.Argument(I)); |
Ada.Command_Line.Argument(I)); |
||
end loop; |
end loop; |
||
end Mulshbang;</ |
end Mulshbang;</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
Line 80: | Line 82: | ||
The namespace = basename = filename minus the extension must be passed as a value to Clojure's -m flag. |
The namespace = basename = filename minus the extension must be passed as a value to Clojure's -m flag. |
||
< |
<syntaxhighlight lang="clojure">":";exec clj -m `basename $0 .clj` $0 ${1+"$@"}</syntaxhighlight> |
||
Alternate shebang, using the [https://github.com/kumarshantanu/lein-exec Leiningen 'exec' plugin]: |
Alternate shebang, using the [https://github.com/kumarshantanu/lein-exec Leiningen 'exec' plugin]: |
||
< |
<syntaxhighlight lang="clojure">":";exec lein exec $0 ${1+"$@"}</syntaxhighlight> |
||
=={{header|Common Lisp}}== |
=={{header|Common Lisp}}== |
||
Line 92: | Line 94: | ||
Here, the script name is passed once to CLISP and once to ext:*args*, which normally omits it. |
Here, the script name is passed once to CLISP and once to ext:*args*, which normally omits it. |
||
< |
<syntaxhighlight lang="lisp">#!/bin/sh |
||
#| |
#| |
||
exec clisp -q -q $0 $0 ${1+"$@"} |
exec clisp -q -q $0 $0 ${1+"$@"} |
||
|#</ |
|#</syntaxhighlight> |
||
=={{header|E}}== |
=={{header|E}}== |
||
Line 103: | Line 105: | ||
In this example, we are including the command name itself in the argument list, which would ordinarily not include it. |
In this example, we are including the command name itself in the argument list, which would ordinarily not include it. |
||
< |
<syntaxhighlight lang="e">#!/bin/sh |
||
>/dev/null; exec rune $0 $0 ${1+"$@"} |
>/dev/null; exec rune $0 $0 ${1+"$@"} |
||
println(`I was called as ${interp.getArgs()[0]}.`)</ |
println(`I was called as ${interp.getArgs()[0]}.`)</syntaxhighlight> |
||
=={{header|Emacs Lisp}}== |
=={{header|Emacs Lisp}}== |
||
< |
<syntaxhighlight lang="lisp">:;exec emacs -batch -l $0 -f main $*</syntaxhighlight> |
||
=={{header|Erlang}}== |
=={{header|Erlang}}== |
||
Line 115: | Line 117: | ||
hello.erl |
hello.erl |
||
< |
<syntaxhighlight lang="erlang">#!/usr/bin/env escript |
||
-module(hello). |
-module(hello). |
||
-export([main/1]). |
-export([main/1]). |
||
main(_) -> io:format("Hello World!~n", []).</ |
main(_) -> io:format("Hello World!~n", []).</syntaxhighlight> |
||
This works fine when the module is run by itself with dot slash: |
This works fine when the module is run by itself with dot slash: |
||
< |
<syntaxhighlight lang="sh">$ ./hello.erl |
||
Hello World!</ |
Hello World!</syntaxhighlight> |
||
But when another Erlang module tries to import the code, or you try to compile manually in erl, you get a syntax error. |
But when another Erlang module tries to import the code, or you try to compile manually in erl, you get a syntax error. |
||
< |
<syntaxhighlight lang="sh">$ erl |
||
Erlang R14B03 (erts-5.8.4) [source] [64-bit] [smp:2:2] [rq:2] [async-threads:0] [hipe] [kernel-poll:false] |
Erlang R14B03 (erts-5.8.4) [source] [64-bit] [smp:2:2] [rq:2] [async-threads:0] [hipe] [kernel-poll:false] |
||
Line 136: | Line 138: | ||
./hello.erl:1: syntax error before: '#' |
./hello.erl:1: syntax error before: '#' |
||
./hello.erl:4: no module definition |
./hello.erl:4: no module definition |
||
error</ |
error</syntaxhighlight> |
||
=={{header|F Sharp|F#}}== |
=={{header|F Sharp|F#}}== |
||
Line 142: | Line 144: | ||
F# scripts may be run with dot-slash notation using the following multiline shebang: |
F# scripts may be run with dot-slash notation using the following multiline shebang: |
||
< |
<syntaxhighlight lang="f#">#light (* |
||
exec fsharpi --exec "$0" --quiet |
exec fsharpi --exec "$0" --quiet |
||
*) |
*) |
||
let main = printfn "Hello World"</ |
let main = printfn "Hello World"</syntaxhighlight> |
||
However, if a script has any dependencies that need to be compiled in, the fsharpi interpreter will not understand how to import them. This means dot-slashing is no longer viable, and the script must be compiled in order to run properly. The shebang can stay, but it is best to remove it, to make clear to users that the script should not be dot-slashed. |
However, if a script has any dependencies that need to be compiled in, the fsharpi interpreter will not understand how to import them. This means dot-slashing is no longer viable, and the script must be compiled in order to run properly. The shebang can stay, but it is best to remove it, to make clear to users that the script should not be dot-slashed. |
||
Line 153: | Line 155: | ||
Factor no longer requires a space after <code>#!</code> as of v0.95. |
Factor no longer requires a space after <code>#!</code> as of v0.95. |
||
< |
<syntaxhighlight lang="factor">#!/usr/bin/env factor -script</syntaxhighlight> |
||
=={{header|Forth|Gforth}}== |
=={{header|Forth|Gforth}}== |
||
We can use Gforth's (non-ANS standard) support for shebangs and the '#' number prefix to make Gforth skip over the shebang without interfering with shell script interpretation. |
We can use Gforth's (non-ANS standard) support for shebangs and the '#' number prefix to make Gforth skip over the shebang without interfering with shell script interpretation. |
||
< |
<syntaxhighlight lang="forth">#! /bin/sh |
||
#0 [IF] \ lines below read by shell but ignored by Gforth |
#0 [IF] \ lines below read by shell but ignored by Gforth |
||
exec gforth \ |
exec gforth \ |
||
Line 166: | Line 168: | ||
[THEN] |
[THEN] |
||
.( hello world) CR BYE |
.( hello world) CR BYE |
||
</syntaxhighlight> |
|||
</lang> |
|||
=={{header| |
=={{header|FreeBASIC}}== |
||
FreeBASIC is a compiled, uninterpreted language, so it cannot be run directly from the Unix command line with a shebang. |
|||
<lang groovy>#!/bin/bash |
|||
script_dir="$(cd $(dirname $0) >/dev/null; pwd -P)" |
|||
However, you can create a shell script that compiles and runs your FreeBASIC program. Here I show an example: |
|||
if [ -z "${GROOVY_HOME}" ] |
|||
then |
|||
echo 'GROOVY_HOME must be defined.' >&2 |
|||
exit 1 |
|||
fi |
|||
<syntaxhighlight lang="vbnet"> |
|||
CLASSPATH="${script_dir}" "${GROOVY_HOME}/bin/groovy" -e "$(sed -e '1,/^!#$/d' $0)" "${@:1}" |
|||
#!/bin/bash |
|||
exit |
|||
# Compile the FreeBASIC program |
|||
!# |
|||
fbc myprogram.bas |
|||
println 'aoeu' |
|||
# Run the compiled program |
|||
</lang> |
|||
./myprogram |
|||
</syntaxhighlight> |
|||
In this script, myprogram.bas is a FreeBASIC program. When you run this shell script, it will compile the FreeBASIC program and then run it. |
|||
=={{header|Go}}== |
=={{header|Go}}== |
||
< |
<syntaxhighlight lang="go">#!/bin/bash |
||
sed -n -e '12,$p' < "$0" > ttmmpp.go |
sed -n -e '12,$p' < "$0" > ttmmpp.go |
||
go build ttmmpp.go |
go build ttmmpp.go |
||
Line 211: | Line 212: | ||
} |
} |
||
} |
} |
||
</syntaxhighlight> |
|||
</lang> |
|||
=={{header|Groovy}}== |
|||
<syntaxhighlight lang="groovy">#!/bin/bash |
|||
script_dir="$(cd $(dirname $0) >/dev/null; pwd -P)" |
|||
if [ -z "${GROOVY_HOME}" ] |
|||
then |
|||
echo 'GROOVY_HOME must be defined.' >&2 |
|||
exit 1 |
|||
fi |
|||
CLASSPATH="${script_dir}" "${GROOVY_HOME}/bin/groovy" -e "$(sed -e '1,/^!#$/d' $0)" "${@:1}" |
|||
exit |
|||
!# |
|||
println 'aoeu' |
|||
</syntaxhighlight> |
|||
=={{header|Haskell}}== |
=={{header|Haskell}}== |
||
Line 217: | Line 234: | ||
{{trans|C}} |
{{trans|C}} |
||
< |
<syntaxhighlight lang="haskell">#!/bin/bash |
||
sed -n -e '7,$p' < "$0" > $0.$$.hs |
sed -n -e '7,$p' < "$0" > $0.$$.hs |
||
ghc $0.$$.hs > /dev/null |
ghc $0.$$.hs > /dev/null |
||
Line 227: | Line 244: | ||
main :: IO () |
main :: IO () |
||
main = getArgs >>= mapM_ (uncurry $ printf "argv[%d] -> %s\n") . zip ([0..] :: [Int])</ |
main = getArgs >>= mapM_ (uncurry $ printf "argv[%d] -> %s\n") . zip ([0..] :: [Int])</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
Line 240: | Line 257: | ||
Or you can 'cheat' by ignoring Bash's complaints about Haskell comments (gives the exact same output as above): |
Or you can 'cheat' by ignoring Bash's complaints about Haskell comments (gives the exact same output as above): |
||
< |
<syntaxhighlight lang="haskell">#!/bin/bash |
||
{- 2> /dev/null |
{- 2> /dev/null |
||
exec runghc $0 $0 $@ |
exec runghc $0 $0 $@ |
||
Line 248: | Line 265: | ||
main :: IO () |
main :: IO () |
||
main = getArgs >>= mapM_ (uncurry $ printf "argv[%d] -> %s\n") . zip ([0..] :: [Int])</ |
main = getArgs >>= mapM_ (uncurry $ printf "argv[%d] -> %s\n") . zip ([0..] :: [Int])</syntaxhighlight> |
||
=={{header|J}}== |
=={{header|J}}== |
||
Line 254: | Line 271: | ||
Assuming this task is asking for a mix of unix shell commands and J, and also that the J binary directory is listed in <code>$PATH</code> |
Assuming this task is asking for a mix of unix shell commands and J, and also that the J binary directory is listed in <code>$PATH</code> |
||
< |
<syntaxhighlight lang="j">#!/bin/sh |
||
# 0 :0 |
# 0 :0 |
||
echo unix shell commands go here |
echo unix shell commands go here |
||
Line 280: | Line 297: | ||
echo p:i. 3 4 |
echo p:i. 3 4 |
||
exit 0 |
exit 0 |
||
</syntaxhighlight> |
|||
</lang> |
|||
'''Notes:''' |
'''Notes:''' |
||
Line 298: | Line 315: | ||
Here's a variant where the shell script tests J's exit code and does something different based on success or failure. |
Here's a variant where the shell script tests J's exit code and does something different based on success or failure. |
||
< |
<syntaxhighlight lang="j">#!/bin/sh |
||
# 0 :0 |
# 0 :0 |
||
echo unix shell commands go here |
echo unix shell commands go here |
||
Line 323: | Line 340: | ||
echo p:i. 3 4 |
echo p:i. 3 4 |
||
exit 0 |
exit 0 |
||
</syntaxhighlight> |
|||
</lang> |
|||
The <code>exit $?</code> line tells the shell interpreter to ignore the J part of the file, and the <code>$?</code> reuses J's exit code as the exit code from the shell instance. |
The <code>exit $?</code> line tells the shell interpreter to ignore the J part of the file, and the <code>$?</code> reuses J's exit code as the exit code from the shell instance. |
||
Note that we've left off the onfail handler within J, and just used a minimal definition to give us a non-zero exit code for the error case. Mostly, the assumption here would be that the error message would not be interesting, and that any failure should be handled by a retry. But you could replace the exit on error line here with the full definition and <code>9!:</code> preparatory bit from the previous example and you could also of course change the <code>1!:2&2</code> lines (<code>1!:2&2</code> is the "low-level" write to stdout mechanism for J - and, yes, those numbers are part of the definition of the language - or at least the "Foreigns" part of the language - note that ultimately all computer languages resolve to things which can be thought of as numbers or sequences of numbers, though some people will vigorously assert other things). |
Note that we've left off the onfail handler within J, and just used a minimal definition to give us a non-zero exit code for the error case. Mostly, the assumption here would be that the error message would not be interesting, and that any failure should be handled by a retry. But you could replace the exit on error line here with the full definition and <code>9!:</code> preparatory bit from the previous example and you could also of course change the <code>1!:2&2</code> lines (<code>1!:2&2</code> is the "low-level" write to stdout mechanism for J - and, yes, those numbers are part of the definition of the language - or at least the "Foreigns" part of the language - note that ultimately all computer languages resolve to things which can be thought of as numbers or sequences of numbers, though some people will vigorously assert other things). |
||
=={{header|jq}}== |
|||
Here is an example using bash: |
|||
<pre> |
|||
#!/bin/sh |
|||
# the following line is ignored by jq provided this one ends with a backslash \ |
|||
exec jq -nef "$0" "$@" |
|||
# jq code follows |
|||
true |
|||
</pre> |
|||
Notice the trailing `\` at the end of the second line. |
|||
Arguments can be passed in to the script, e.g. using the --arg NAME VALUE option. |
|||
=={{header|Julia}}== |
|||
<syntaxhighlight lang="julia"> |
|||
#!/bin/sh |
|||
#= |
|||
echo Julia will ignore as commented all text between #= and =# |
|||
echo which allows us to place arbitrary unix shell code here |
|||
echo perhaps to change environment settings for Julia or |
|||
echo set the directory prior to starting the Julia program. |
|||
echo for example: |
|||
cd /user/meeting/working |
|||
echo then start the Julia program |
|||
exec julia "$0" "$@" |
|||
# comments ignored by Julia end here --> =# |
|||
function countto(n) |
|||
i = zero(n) |
|||
println("Counting to $n...") |
|||
while i < n |
|||
i += 1 |
|||
end |
|||
println("Done!") |
|||
end |
|||
@time countto(10^10) |
|||
</syntaxhighlight> |
|||
=={{header|MATLAB}}== |
=={{header|MATLAB}}== |
||
Line 335: | Line 393: | ||
~/bin/shmatlab%: |
~/bin/shmatlab%: |
||
< |
<syntaxhighlight lang="bash">#!/bin/sh |
||
matlab -nojvm -nodisplay -nosplash -r "varargin = regexp('${1+"$@"}', ' ', 'split'); nvarargin = length(varargin); run('$1'); exit" | tail -n +16 |
matlab -nojvm -nodisplay -nosplash -r "varargin = regexp('${1+"$@"}', ' ', 'split'); nvarargin = length(varargin); run('$1'); exit" | tail -n +16 |
||
</syntaxhighlight> |
|||
</lang> |
|||
args.m: |
args.m: |
||
< |
<syntaxhighlight lang="matlab">'shmatlab'% $0 ${1+"$@"} |
||
'exit'; |
'exit'; |
||
for i = 1:nvarargin |
for i = 1:nvarargin |
||
disp(varargin{i}); |
disp(varargin{i}); |
||
end</ |
end</syntaxhighlight> |
||
Example: |
Example: |
||
Line 357: | Line 415: | ||
c |
c |
||
</pre> |
</pre> |
||
=={{header|Nim}}== |
|||
In Nim, multiline comments start with <code>#[</code> and end with <code>]#</code>. This allows to build a polyglot program which can be run as a shell script and compiled as a Nim program. |
|||
<syntaxhighlight lang="nim">#!/bin/bash |
|||
#[ |
|||
echo Put here code to run as a shell script. |
|||
exit # This is needed to ignore last part of the file. |
|||
]# |
|||
# Nim program |
|||
echo "Executing Nim program"</syntaxhighlight> |
|||
=={{header|OCaml}}== |
=={{header|OCaml}}== |
||
Line 362: | Line 432: | ||
ocamlc hates shebangs, so much trickery is needed. The number of underscores in the dummy kkkk identifier corresponds to the number of bash strings in the shebang. Thus, core library .cma files can be specified this way in interpreted mode, though accessing other OCaml scripts requires compiling them first, and referencing the .cmo's here. |
ocamlc hates shebangs, so much trickery is needed. The number of underscores in the dummy kkkk identifier corresponds to the number of bash strings in the shebang. Thus, core library .cma files can be specified this way in interpreted mode, though accessing other OCaml scripts requires compiling them first, and referencing the .cmo's here. |
||
< |
<syntaxhighlight lang="ocaml">if true then ignore begin let kkkk _ _ _ _ = 0 in kkkk |
||
"exec" "ocaml" "$0" "$@" + let fi = 0 and exit _ _ = 0 in if false |
"exec" "ocaml" "$0" "$@" + let fi = 0 and exit _ _ = 0 in if false |
||
then exit |
then exit |
||
Line 369: | Line 439: | ||
end;; |
end;; |
||
let main = print_endline "Hello World!"</ |
let main = print_endline "Hello World!"</syntaxhighlight> |
||
Example: |
Example: |
||
Line 391: | Line 461: | ||
=={{header|PARI/GP}}== |
=={{header|PARI/GP}}== |
||
The PARI equivalent to a multiline shebang is a collection of <code>GP;</code> lines: |
The PARI equivalent to a multiline shebang is a collection of <code>GP;</code> lines: |
||
<syntaxhighlight lang="c">/* |
|||
<lang C>/* |
|||
GP;install("C_function_name","G","GP_name","./filename.gp.so"); |
GP;install("C_function_name","G","GP_name","./filename.gp.so"); |
||
GP;addhelp(GP_name, "GP_name(n): Computes the foo of bar(n)."); |
GP;addhelp(GP_name, "GP_name(n): Computes the foo of bar(n)."); |
||
*/</ |
*/</syntaxhighlight> |
||
These commands are passed to GP when invoked by gp2c. |
These commands are passed to GP when invoked by gp2c. |
||
=={{header|Perl}}== |
=={{header|Perl}}== |
||
From <code>perldoc perlrun</code>, the following is supposed to find perl one way or another under sh, csh or perl. |
From <code>perldoc perlrun</code>, the following is supposed to find perl one way or another under sh, csh or perl. |
||
< |
<syntaxhighlight lang="perl">#!/usr/bin/perl |
||
eval '(exit $?0)' && eval 'exec perl -wS $0 ${1+"$@"}' |
eval '(exit $?0)' && eval 'exec perl -wS $0 ${1+"$@"}' |
||
& eval 'exec /usr/bin/perl -wS $0 $argv:q' |
& eval 'exec /usr/bin/perl -wS $0 $argv:q' |
||
if $running_under_some_shell;</ |
if $running_under_some_shell;</syntaxhighlight> |
||
=={{header|Perl 6}}== |
|||
{{ |
=={{header|Phix}}== |
||
Obviously this is not pwa/p2js compatible, since you cannot run bash or sed (with redirection) or phix or 'rm tmp.eu' from within a browser, and is only intended to be run on Linux, though you could perhaps run it on Windows but only in some kind of bash shell. |
|||
<lang perl6>#!/usr/local/bin/perl6 |
|||
<!--<syntaxhighlight lang="phix">--> |
|||
eval '(exit $?0)' && eval 'exec perl6 $0 ${1+"$@"}' |
|||
<span style="color: #000000;">#!/bin/bash |
|||
& eval 'exec perl6 $0 $argv:q' |
|||
sed -n -e '7,$p' < "$0" > tmp.eu |
|||
if 0;</lang> |
|||
\path\to\phix tmp.eu "$@" |
|||
STATUS=$? |
|||
rm tmp.eu |
|||
exit $STATUS</span> |
|||
<span style="color: #008080;">without</span> <span style="color: #008080;">js</span> <span style="color: #000080;font-style:italic;">-- (not that pwa/p2js would get this far!)</span> |
|||
<span style="color: #0000FF;">?</span><span style="color: #7060A8;">command_line</span><span style="color: #0000FF;">()</span> |
|||
<!--</syntaxhighlight>--> |
|||
Alternatively it was not particularly difficult, just for this task, to add #[ and #] handling, just like /* and */, to both desktop/Phix and pwa/p2js.<br> |
|||
Note that I simply cannot see how #! ... !# could ever work, in any programming language, that is while also allowing single line shebangs with no closing !#.<br> |
|||
Hence the following (partly based on the Julia entry) now (1.0.2) also works fine, with no detrimental (or beneficial) effect either on (standard) Windows or under pwa/p2js: |
|||
<!--<syntaxhighlight lang="phix">(phixonline)--> |
|||
<span style="color: #00000;font-style:italic;">#!/bin/bash |
|||
#[ |
|||
echo Phix ignores all text between #[ and #] in exactly the same way as /* and */ |
|||
echo (both "and" are nested comments), allowing arbitrary shell code, for example |
|||
cd /user/project/working |
|||
exec /path/to/phix "$0" "$@" |
|||
exit # may be needed for the shell to ignore the rest of this file. |
|||
# comments ingored by Phix end here -> #]</span> |
|||
<span style="color: #008080;">with</span> <span style="color: #008080;">javascript_semantics</span> |
|||
<span style="color: #7060A8;">puts</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"This is Phix code\n"</span><span style="color: #0000FF;">)</span> |
|||
<!--</syntaxhighlight>--> |
|||
=={{header|PicoLisp}}== |
=={{header|PicoLisp}}== |
||
We can use a multi-line comment #{ ... }# to hide the shell commands from Lisp. The opening #{ in turn is a coment for the shell. |
We can use a multi-line comment #{ ... }# to hide the shell commands from Lisp. The opening #{ in turn is a coment for the shell. |
||
< |
<syntaxhighlight lang="picolisp">#!/bin/bash |
||
#{ |
#{ |
||
exec pil $0 foo bar |
exec pil $0 foo bar |
||
Line 419: | Line 511: | ||
# Lisp code |
# Lisp code |
||
(println (cadr (file)) (opt) (opt)) |
(println (cadr (file)) (opt) (opt)) |
||
(bye)</ |
(bye)</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre>$ ./myScript |
<pre>$ ./myScript |
||
Line 426: | Line 518: | ||
=={{header|Pike}}== |
=={{header|Pike}}== |
||
we use a multiline comment to hide the shell command from pike, and we can use a preprocessor directive to hide the comment begin from the shell. |
we use a multiline comment to hide the shell command from pike, and we can use a preprocessor directive to hide the comment begin from the shell. |
||
< |
<syntaxhighlight lang="pike">#!/bin/bash |
||
#define foo foo /* |
#define foo foo /* |
||
exec pike $0 hello world |
exec pike $0 hello world |
||
Line 434: | Line 526: | ||
{ |
{ |
||
write("%O\n", argv); |
write("%O\n", argv); |
||
}</ |
}</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
Line 447: | Line 539: | ||
This style of shebang would also work with other languages that use double dashes for comments, though most of them (Lua, Haskell) already support traditional #!... shebangs. |
This style of shebang would also work with other languages that use double dashes for comments, though most of them (Lua, Haskell) already support traditional #!... shebangs. |
||
< |
<syntaxhighlight lang="postgresql">--() { :; }; exec psql -f "$0" |
||
SELECT 'Hello World!';</ |
SELECT 'Hello World!';</syntaxhighlight> |
||
=={{header|Python}}== |
=={{header|Python}}== |
||
We can use multiple strings to make the shell commands do nothing from Python (actually they become the module docstring.). |
We can use multiple strings to make the shell commands do nothing from Python (actually they become the module docstring.). |
||
< |
<syntaxhighlight lang="python">#!/bin/bash |
||
"exec" "python" "$0" |
"exec" "python" "$0" |
||
print "Hello World"</ |
print "Hello World"</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre>$ ./myScript |
<pre>$ ./myScript |
||
Line 463: | Line 555: | ||
Control structures (if/for/etc.) can't be quoted, |
Control structures (if/for/etc.) can't be quoted, |
||
but one can use the following to embed any script: |
but one can use the following to embed any script: |
||
< |
<syntaxhighlight lang="python">#!/bin/sh |
||
"true" '''\' |
"true" '''\' |
||
if [ -L $0 ]; then |
if [ -L $0 ]; then |
||
Line 473: | Line 565: | ||
__doc__ = """module docstring""" |
__doc__ = """module docstring""" |
||
print "Hello World"</ |
print "Hello World"</syntaxhighlight> |
||
Here we use a) the code <nowiki>'''\'</nowiki> translates to \ in shell, but opens a multi-line string in Python; b) the true command ignores its argument, c) we always exit before the ending <nowiki>'''</nowiki> so that the shell interpreter never reads it. Also, remember to set any docstrings by assigning to __doc__ since the docstring is already used for the shell script. |
Here we use a) the code <nowiki>'''\'</nowiki> translates to \ in shell, but opens a multi-line string in Python; b) the true command ignores its argument, c) we always exit before the ending <nowiki>'''</nowiki> so that the shell interpreter never reads it. Also, remember to set any docstrings by assigning to __doc__ since the docstring is already used for the shell script. |
||
=={{header|Racket}}== |
=={{header|Racket}}== |
||
<syntaxhighlight lang="racket"> |
|||
<lang Racket> |
|||
#!/bin/sh |
#!/bin/sh |
||
#| -*- scheme -*- |
#| -*- scheme -*- |
||
Line 492: | Line 584: | ||
(printf "argument: ~a\nexecuted as: ~a\n" |
(printf "argument: ~a\nexecuted as: ~a\n" |
||
arg (find-system-path 'exec-file))) |
arg (find-system-path 'exec-file))) |
||
</syntaxhighlight> |
|||
</lang> |
|||
=={{header|Raku}}== |
|||
(formerly Perl 6) |
|||
<syntaxhighlight lang="raku" line>#!/usr/local/bin/raku |
|||
use MONKEY; EVAL '(exit $?0)' && EVAL 'exec rake $0 ${1+"$@"}' |
|||
& EVAL 'exec raku $0 $argv:q' |
|||
if 0;</syntaxhighlight> |
|||
=={{header|Ruby}}== |
=={{header|Ruby}}== |
||
Line 501: | Line 601: | ||
This script works both ways: either <code>/bin/sh script.rb</code> or <code>ruby script.rb</code> would run multiple lines of shell commands, and then start Ruby. |
This script works both ways: either <code>/bin/sh script.rb</code> or <code>ruby script.rb</code> would run multiple lines of shell commands, and then start Ruby. |
||
< |
<syntaxhighlight lang="ruby">#!/bin/sh |
||
# Insert shell code here! |
# Insert shell code here! |
||
Line 523: | Line 623: | ||
ARGV.each_with_index do |arg, i| |
ARGV.each_with_index do |arg, i| |
||
puts " ARGV[#{i}]: #{arg}" |
puts " ARGV[#{i}]: #{arg}" |
||
end</ |
end</syntaxhighlight> |
||
When running <code>/bin/sh scratch.rb</code>, the shell: |
When running <code>/bin/sh scratch.rb</code>, the shell: |
||
Line 543: | Line 643: | ||
The scalac compiler does not. |
The scalac compiler does not. |
||
< |
<syntaxhighlight lang="scala"> |
||
#!/bin/bash |
#!/bin/bash |
||
FOO=bar |
FOO=bar |
||
Line 559: | Line 659: | ||
} |
} |
||
println("fact(5) = " + fact(5));</ |
println("fact(5) = " + fact(5));</syntaxhighlight> |
||
=={{header|Scheme}}== |
=={{header|Scheme}}== |
||
{{works with|Chicken Scheme}} |
{{works with|Chicken Scheme}} |
||
< |
<syntaxhighlight lang="scheme">#!/usr/bin/env csi -ss</syntaxhighlight> |
||
=={{header|Sidef}}== |
=={{header|Sidef}}== |
||
< |
<syntaxhighlight lang="ruby">#!/bin/sh |
||
#`(if running under some shell) { |
#`(if running under some shell) { |
||
Line 573: | Line 673: | ||
} |
} |
||
say "Hello, #{ARGV[0]}!"</ |
say "Hello, #{ARGV[0]}!"</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
Line 588: | Line 688: | ||
=={{header|Smalltalk}}== |
=={{header|Smalltalk}}== |
||
< |
<syntaxhighlight lang="smalltalk">"exec" "gst" "-f" "$0" "$0" "$@"</syntaxhighlight> |
||
=={{header|SQL PL}}== |
=={{header|SQL PL}}== |
||
Line 594: | Line 694: | ||
Based on the Postgres shebang, it works the same with IBM Db2. |
Based on the Postgres shebang, it works the same with IBM Db2. |
||
<syntaxhighlight lang="sql pl"> |
|||
<lang sql> |
|||
--() { :; }; exec db2 -txf "$0" |
--() { :; }; exec db2 -txf "$0" |
||
get instance; |
get instance; |
||
connect; |
connect to sample; |
||
select 'Hello' from sysibm.sysdummy1; |
select 'Hello' from sysibm.sysdummy1; |
||
values current date; |
values current date; |
||
</syntaxhighlight> |
|||
</lang> |
|||
Output: |
Output: |
||
<pre> |
<pre> |
||
Line 612: | Line 712: | ||
Database Connection Information |
Database Connection Information |
||
Database server = DB2/LINUXX8664 |
Database server = DB2/LINUXX8664 11.1.1 |
||
SQL authorization ID = |
SQL authorization ID = DB2INST1 |
||
Local database alias = |
Local database alias = SAMPLE |
||
Line 628: | Line 728: | ||
=={{header|Tcl}}== |
=={{header|Tcl}}== |
||
It is normal to use a line like this: |
It is normal to use a line like this: |
||
<lang |
<syntaxhighlight lang="tcl">#!/usr/bin/env tclsh</syntaxhighlight> |
||
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: |
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: |
||
< |
<syntaxhighlight lang="tcl">#!/bin/sh |
||
# Next line is comment in Tcl, but not in sh... \ |
# Next line is comment in Tcl, but not in sh... \ |
||
exec tclsh "$0" ${1+"$@"}</ |
exec tclsh "$0" ${1+"$@"}</syntaxhighlight> |
||
Additional complexity can be added so long as the lines for the shell are commented in a Tcl sense. |
Additional complexity can be added so long as the lines for the shell are commented in a Tcl sense. |
||
Line 657: | Line 757: | ||
arg[3]="3" |
arg[3]="3" |
||
$</pre> |
$</pre> |
||
=={{header|Wren}}== |
|||
Wren doesn't support multiline shebangs as such. Anything after the first line is always interpreted as Wren code. |
|||
You can get around this by placing shell commands in a block comment after a single line shebang. So (ignoring the strange error message) the following works: |
|||
<syntaxhighlight lang="wren">#!/bin/bash |
|||
/* |
|||
echo "Hello from bash" |
|||
/bin/wren Multiline_shebang.wren |
|||
exit |
|||
*/ |
|||
System.print("Hello from Wren")</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
$ chmod +x Multiline_shebang.wren |
|||
$ ./Multiline_shebang.wren |
|||
./Multiline_shebang.wren: line 2: /bin: Is a directory |
|||
Hello from bash |
|||
Hello from Wren |
|||
</pre> |
|||
<br> |
|||
However, we don't actually need a multiline shebang to get the script name as this is always passed automatically as the second command line argument when the Wren process is spawned, the first argument being the Wren executable itself. Moreover, if a single line shebang is used, the third argument will be the shell command used to execute the script. |
|||
<syntaxhighlight lang="wren">#!/bin/wren Multiline_shebang_2.wren |
|||
import "os" for Process |
|||
var args = Process.allArguments |
|||
System.print("Executable : %(args[0])") |
|||
System.print("Script name : %(args[1])") |
|||
System.print("Shell command : %(args[2])") |
|||
if (args.count > 3) { |
|||
for (i in 3...args.count) System.print("Argument %(i-2) : %(args[i])") |
|||
}</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
$ chmod +x Multiline_shebang_2.wren |
|||
$ ./Multiline_shebang_2.wren one two three |
|||
Executable : /bin/wren |
|||
Script name : Multiline_shebang_2.wren |
|||
Shell command : ./Multiline_shebang_2.wren |
|||
Argument 1 : one |
|||
Argument 2 : two |
|||
Argument 3 : three |
|||
</pre> |
|||
=={{header|zkl}}== |
=={{header|zkl}}== |
||
Line 662: | Line 807: | ||
File foo.zkl (the .zkl extension is needed): |
File foo.zkl (the .zkl extension is needed): |
||
< |
<syntaxhighlight lang="zkl">#!/bin/sh |
||
#<<<# |
#<<<# |
||
echo "A shell script in a zkl program ($0)" |
echo "A shell script in a zkl program ($0)" |
||
Line 669: | Line 814: | ||
exit |
exit |
||
#<<<# |
#<<<# |
||
println("The shell script says ",vm.arglist.concat(" "));</ |
println("The shell script says ",vm.arglist.concat(" "));</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre> |
<pre> |
Latest revision as of 13:26, 16 May 2024
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 some shell (perhaps Bash) so that they can be executed. In other words, Polyglots.
Warning: Using a multiline shebang of the form #!/bin/sh ... exec ... !#
will set the code's mimetype to text/x-shellscript
, which creates problems such as Emacs treating the file as a shell script, no matter which language and file extension it really uses.
- See also
- Native shebang - where the "program loaded" is of the actual native task language.
Ada
#!/bin/bash
sed -n -e '7,$p' < "$0" > mulshbang.adb
gnatmake -q mulshbang
./mulshbang $*
rm mulshbang*
exit
with Ada.Text_IO, Ada.Command_Line; -- first line of Ada program
procedure Mulshbang is
use Ada.Text_IO;
begin
Put_Line("Name: " & Ada.Command_Line.Command_Name);
for I in 1 .. Ada.Command_Line.Argument_Count loop
Put_Line(" Arg" & Integer'Image(I) & ": " &
Ada.Command_Line.Argument(I));
end loop;
end Mulshbang;
- Output:
>./adamulshbang Name: ./mulshbang >./adamulshbang one two three Name: ./mulshbang Arg 1: one Arg 2: two Arg 3: three
C
#!/bin/bash sed -n -e '7,$p' < "$0" | /usr/bin/gcc -x c -o "$0.$$.out" - $0.$$.out "$0" "$@" STATUS=$? rm $0.$$.out exit $STATUS #include <stdio.h> int main(int argc, char **argv) { int i; for (i = 0; i < argc; i++) printf("argv[%d] -> %s\n", i, argv[i]); return 0; }
Test runs:
$ ./cmulshbang.c argv[0] -> ./cmulshbang.c.4062.out argv[1] -> ./cmulshbang.c $ ./cmulshbang.c 1 argv[0] -> ./cmulshbang.c.4071.out argv[1] -> ./cmulshbang.c argv[2] -> 1 $ ./cmulshbang.c 1 2 argv[0] -> ./cmulshbang.c.4080.out argv[1] -> ./cmulshbang.c argv[2] -> 1 argv[3] -> 2
Student exercise: use a stable filename for the executable, e.g. "$0.out"
. Do not remove it, and only recompile it if the script's timestamp is newer than that of the executable.
Clojure
The namespace = basename = filename minus the extension must be passed as a value to Clojure's -m flag.
":";exec clj -m `basename $0 .clj` $0 ${1+"$@"}
Alternate shebang, using the Leiningen 'exec' plugin:
":";exec lein exec $0 ${1+"$@"}
Common Lisp
Here, the script name is passed once to CLISP and once to ext:*args*, which normally omits it.
#!/bin/sh
#|
exec clisp -q -q $0 $0 ${1+"$@"}
|#
E
E uses only “#” for line comments, like the shell, so there is no straightforward answer. We can abuse the fact that “>” is also a line comment to achieve this effect. Note that a “>” line comment should ordinarily only occur as part of Updoc (test/documentation) text, so this is not good practice.
In this example, we are including the command name itself in the argument list, which would ordinarily not include it.
#!/bin/sh
>/dev/null; exec rune $0 $0 ${1+"$@"}
println(`I was called as ${interp.getArgs()[0]}.`)
Emacs Lisp
:;exec emacs -batch -l $0 -f main $*
Erlang
hello.erl
#!/usr/bin/env escript
-module(hello).
-export([main/1]).
main(_) -> io:format("Hello World!~n", []).
This works fine when the module is run by itself with dot slash:
$ ./hello.erl
Hello World!
But when another Erlang module tries to import the code, or you try to compile manually in erl, you get a syntax error.
$ erl
Erlang R14B03 (erts-5.8.4) [source] [64-bit] [smp:2:2] [rq:2] [async-threads:0] [hipe] [kernel-poll:false]
Eshell V5.8.4 (abort with ^G)
1> c(hello).
./hello.erl:1: syntax error before: '#'
./hello.erl:4: no module definition
error
F#
F# scripts may be run with dot-slash notation using the following multiline shebang:
#light (*
exec fsharpi --exec "$0" --quiet
*)
let main = printfn "Hello World"
However, if a script has any dependencies that need to be compiled in, the fsharpi interpreter will not understand how to import them. This means dot-slashing is no longer viable, and the script must be compiled in order to run properly. The shebang can stay, but it is best to remove it, to make clear to users that the script should not be dot-slashed.
Factor
Factor no longer requires a space after #!
as of v0.95.
#!/usr/bin/env factor -script
Forth
We can use Gforth's (non-ANS standard) support for shebangs and the '#' number prefix to make Gforth skip over the shebang without interfering with shell script interpretation.
#! /bin/sh
#0 [IF] \ lines below read by shell but ignored by Gforth
exec gforth \
-m 256M \
-d 16M \
"$0" "$@"
[THEN]
.( hello world) CR BYE
FreeBASIC
FreeBASIC is a compiled, uninterpreted language, so it cannot be run directly from the Unix command line with a shebang.
However, you can create a shell script that compiles and runs your FreeBASIC program. Here I show an example:
#!/bin/bash
# Compile the FreeBASIC program
fbc myprogram.bas
# Run the compiled program
./myprogram
In this script, myprogram.bas is a FreeBASIC program. When you run this shell script, it will compile the FreeBASIC program and then run it.
Go
#!/bin/bash
sed -n -e '12,$p' < "$0" > ttmmpp.go
go build ttmmpp.go
rm ttmmpp.go
binfile="${0%.*}"
mv ttmmpp $binfile
$binfile "$@"
STATUS=$?
rm $binfile
exit $STATUS
######## Go Code start on line 12
package main
import (
"fmt"
"os"
)
func main() {
for i, x := range os.Args {
if i == 0 {
fmt.Printf("This program is named %s.\n", x)
} else {
fmt.Printf("the argument #%d is %s\n", i, x)
}
}
}
Groovy
#!/bin/bash
script_dir="$(cd $(dirname $0) >/dev/null; pwd -P)"
if [ -z "${GROOVY_HOME}" ]
then
echo 'GROOVY_HOME must be defined.' >&2
exit 1
fi
CLASSPATH="${script_dir}" "${GROOVY_HOME}/bin/groovy" -e "$(sed -e '1,/^!#$/d' $0)" "${@:1}"
exit
!#
println 'aoeu'
Haskell
#!/bin/bash
sed -n -e '7,$p' < "$0" > $0.$$.hs
ghc $0.$$.hs > /dev/null
./$0.$$ "$0" "$@"
rm $0.$$*
exit
import Text.Printf
import System.Environment
main :: IO ()
main = getArgs >>= mapM_ (uncurry $ printf "argv[%d] -> %s\n") . zip ([0..] :: [Int])
- Output:
$ ./multibang.hs argv[0] -> ./multibang.hs $ ./multibang.hs Goodbye, World! argv[0] -> ./multibang.hs argv[1] -> Goodbye, argv[2] -> World!
Or you can 'cheat' by ignoring Bash's complaints about Haskell comments (gives the exact same output as above):
#!/bin/bash
{- 2> /dev/null
exec runghc $0 $0 $@
-}
import Text.Printf
import System.Environment
main :: IO ()
main = getArgs >>= mapM_ (uncurry $ printf "argv[%d] -> %s\n") . zip ([0..] :: [Int])
J
Assuming this task is asking for a mix of unix shell commands and J, and also that the J binary directory is listed in $PATH
#!/bin/sh
# 0 :0
echo unix shell commands go here
echo presumably this will condition the environment
echo for example:
cd working-directory
echo or maybe you want to modify $PATH, ... whatever...
echo then start up J:
exec jconsole "$0" "$@"
)
NB. exit on error
onfail_z_=:3 :0
1!:2&2 ARGV
1!:2&2]13!:12'' NB. display error message
2!:55>:13!:11'' NB. exit with 1 origin error number
)
9!:27 'onfail 1'
9!:29]1
NB. and then the rest of the file is J
echo 'hi!'
echo 'your command line arguments were:'
echo ARGV
echo p:i. 3 4
exit 0
Notes:
The #!/bin/sh
line is interpreted by J as a verb train with no arguments - in other words, it is ignored.
The # 0 :0
line is interpreted by shell as a comment and by J as the beginning of a multiline "hereis" script which basically ignores everything up to the lone right parenthesis.
So then it's just regular shell script up until the line where we turn control over to J. On that line, we use exec
(so that the shell process does not hang around, waiting for J to finish - J takes over the current process). And we pass any shell script command line arguments on to J.
On the J side of the fence, we presumably want this code to behave like a normal unix module, so we need to override J's default behavior (which is to provide the J command line). 9!:29]1[9!:27'2!:55]1
is a bit of magic that accomplishes that: it stacks a command to exit with exit code 1 to be executed when we reach the command line. So any errors will terminate the program.
Next, we run the system J profile so that we have all of the standard stuff that that provides. (Or leave this out if that's what you want.)
Finally we do some J stuff and then exit. If everything goes right, the command line exit we stacked earlier just gets ignored.
Here's a variant where the shell script tests J's exit code and does something different based on success or failure.
#!/bin/sh
# 0 :0
echo unix shell commands go here
echo presumably this will condition the environment
echo for example:
cd working-directory
echo or maybe you want to modify $PATH, ... whatever...
echo then start up J:
if jconsole -jprofile "$0" "$@"; then
echo success
else
echo failure
fi
exit $?
)
9!:29]1[9!:27'2!:55]1' NB. exit on error
(3 :'0!:0 y')<BINPATH,'/profile.ijs'
NB. and then the rest of the file is J
echo 'hi!'
echo 'your command line arguments were:'
echo ARGV
echo p:i. 3 4
exit 0
The exit $?
line tells the shell interpreter to ignore the J part of the file, and the $?
reuses J's exit code as the exit code from the shell instance.
Note that we've left off the onfail handler within J, and just used a minimal definition to give us a non-zero exit code for the error case. Mostly, the assumption here would be that the error message would not be interesting, and that any failure should be handled by a retry. But you could replace the exit on error line here with the full definition and 9!:
preparatory bit from the previous example and you could also of course change the 1!:2&2
lines (1!:2&2
is the "low-level" write to stdout mechanism for J - and, yes, those numbers are part of the definition of the language - or at least the "Foreigns" part of the language - note that ultimately all computer languages resolve to things which can be thought of as numbers or sequences of numbers, though some people will vigorously assert other things).
jq
Here is an example using bash:
#!/bin/sh # the following line is ignored by jq provided this one ends with a backslash \ exec jq -nef "$0" "$@" # jq code follows true
Notice the trailing `\` at the end of the second line.
Arguments can be passed in to the script, e.g. using the --arg NAME VALUE option.
Julia
#!/bin/sh
#=
echo Julia will ignore as commented all text between #= and =#
echo which allows us to place arbitrary unix shell code here
echo perhaps to change environment settings for Julia or
echo set the directory prior to starting the Julia program.
echo for example:
cd /user/meeting/working
echo then start the Julia program
exec julia "$0" "$@"
# comments ignored by Julia end here --> =#
function countto(n)
i = zero(n)
println("Counting to $n...")
while i < n
i += 1
end
println("Done!")
end
@time countto(10^10)
MATLAB
Unlike Octave, MATLAB has no built-in support for shebangs. In fact, several tricks are required to even approximate a shebang, due to the byzantine way that MATLAB structures scripts and function files.
~/bin/shmatlab%:
#!/bin/sh
matlab -nojvm -nodisplay -nosplash -r "varargin = regexp('${1+"$@"}', ' ', 'split'); nvarargin = length(varargin); run('$1'); exit" | tail -n +16
args.m:
'shmatlab'% $0 ${1+"$@"}
'exit';
for i = 1:nvarargin
disp(varargin{i});
end
Example:
$ ./args.m a b c ./args.m a b c
Nim
In Nim, multiline comments start with #[
and end with ]#
. This allows to build a polyglot program which can be run as a shell script and compiled as a Nim program.
#!/bin/bash
#[
echo Put here code to run as a shell script.
exit # This is needed to ignore last part of the file.
]#
# Nim program
echo "Executing Nim program"
OCaml
ocamlc hates shebangs, so much trickery is needed. The number of underscores in the dummy kkkk identifier corresponds to the number of bash strings in the shebang. Thus, core library .cma files can be specified this way in interpreted mode, though accessing other OCaml scripts requires compiling them first, and referencing the .cmo's here.
if true then ignore begin let kkkk _ _ _ _ = 0 in kkkk
"exec" "ocaml" "$0" "$@" + let fi = 0 and exit _ _ = 0 in if false
then exit
fi
true else 0
end;;
let main = print_endline "Hello World!"
Example:
$ head -n 2 she.ml if true then ignore begin let kkkk _ _ _ _ _ _ = 0 in kkkk "exec" "ocaml" "$0" "unix.cma" "graphics.cma" "$@" + let fi = 0 and exit _ _ = 0 in if false $ ocaml she.ml Hello World! $ /bin/bash she.ml Hello World! $ ocamlc -o she.byte she.ml $ ./she.byte Hello World! $ ocamlopt -o she.opt she.ml $ ./she.opt Hello World!
PARI/GP
The PARI equivalent to a multiline shebang is a collection of GP;
lines:
/*
GP;install("C_function_name","G","GP_name","./filename.gp.so");
GP;addhelp(GP_name, "GP_name(n): Computes the foo of bar(n).");
*/
These commands are passed to GP when invoked by gp2c.
Perl
From perldoc perlrun
, the following is supposed to find perl one way or another under sh, csh or 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;
Phix
Obviously this is not pwa/p2js compatible, since you cannot run bash or sed (with redirection) or phix or 'rm tmp.eu' from within a browser, and is only intended to be run on Linux, though you could perhaps run it on Windows but only in some kind of bash shell.
#!/bin/bash sed -n -e '7,$p' < "$0" > tmp.eu \path\to\phix tmp.eu "$@" STATUS=$? rm tmp.eu exit $STATUS without js -- (not that pwa/p2js would get this far!) ?command_line()
Alternatively it was not particularly difficult, just for this task, to add #[ and #] handling, just like /* and */, to both desktop/Phix and pwa/p2js.
Note that I simply cannot see how #! ... !# could ever work, in any programming language, that is while also allowing single line shebangs with no closing !#.
Hence the following (partly based on the Julia entry) now (1.0.2) also works fine, with no detrimental (or beneficial) effect either on (standard) Windows or under pwa/p2js:
#!/bin/bash #[ echo Phix ignores all text between #[ and #] in exactly the same way as /* and */ echo (both "and" are nested comments), allowing arbitrary shell code, for example cd /user/project/working exec /path/to/phix "$0" "$@" exit # may be needed for the shell to ignore the rest of this file. # comments ingored by Phix end here -> #] with javascript_semantics puts(1,"This is Phix code\n")
PicoLisp
We can use a multi-line comment #{ ... }# to hide the shell commands from Lisp. The opening #{ in turn is a coment for the shell.
#!/bin/bash
#{
exec pil $0 foo bar
# }#
# Lisp code
(println (cadr (file)) (opt) (opt))
(bye)
- Output:
$ ./myScript "myScript" "foo" "bar"
Pike
we use a multiline comment to hide the shell command from pike, and we can use a preprocessor directive to hide the comment begin from the shell.
#!/bin/bash
#define foo foo /*
exec pike $0 hello world
*/
int main(int argc, array argv)
{
write("%O\n", argv);
}
- Output:
({ /* 3 elements */ "/local/users/mbaehr/src/pike/multiline-shebang/multiline-shebang.pike", "hello", "world" })
PostgreSQL
This style of shebang would also work with other languages that use double dashes for comments, though most of them (Lua, Haskell) already support traditional #!... shebangs.
--() { :; }; exec psql -f "$0"
SELECT 'Hello World!';
Python
We can use multiple strings to make the shell commands do nothing from Python (actually they become the module docstring.).
#!/bin/bash
"exec" "python" "$0"
print "Hello World"
- Output:
$ ./myScript Hello World
Control structures (if/for/etc.) can't be quoted, but one can use the following to embed any script:
#!/bin/sh
"true" '''\'
if [ -L $0 ]; then
...
exec "$interpreter" "$@"
exit 127
'''
__doc__ = """module docstring"""
print "Hello World"
Here we use a) the code '''\' translates to \ in shell, but opens a multi-line string in Python; b) the true command ignores its argument, c) we always exit before the ending ''' so that the shell interpreter never reads it. Also, remember to set any docstrings by assigning to __doc__ since the docstring is already used for the shell script.
Racket
#!/bin/sh
#| -*- scheme -*-
# this is sh code
echo running "$0", passing it into itself as an argument
exec racket -tm "$0" "$0"
|#
#lang racket
(provide main)
(define (main arg)
(printf "argument: ~a\nexecuted as: ~a\n"
arg (find-system-path 'exec-file)))
Raku
(formerly Perl 6)
#!/usr/local/bin/raku
use MONKEY; EVAL '(exit $?0)' && EVAL 'exec rake $0 ${1+"$@"}'
& EVAL 'exec raku $0 $argv:q'
if 0;
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.
#!/bin/sh
# 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
# Switch from shell to Ruby.
exec ${RUBY-ruby} -x "$0" --coming-from-sh "$@"
#!ruby
ARGV[0] == "--coming-from-sh" or exec "/bin/sh", $0, *ARGV
ARGV.shift
# Insert Ruby code here!
puts "Ruby running #$0"
ARGV.each_with_index do |arg, i|
puts " ARGV[#{i}]: #{arg}"
end
When running /bin/sh scratch.rb
, the shell:
- ignores
#!/bin/sh
, because it is a comment. - runs multiple lines of shell code.
- 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.
Scala
The scala(1) interpreter parses a header section. The scalac compiler does not.
#!/bin/bash
FOO=bar
scala $0 $@
exit
!#
def fact(n : Int) : Int = {
var i = n ;
var a = 1 ;
while (i > 0) {
a = a*i ;
i -= 1 ;
}
return a ;
}
println("fact(5) = " + fact(5));
Scheme
#!/usr/bin/env csi -ss
Sidef
#!/bin/sh
#`(if running under some shell) {
eval 'exec /usr/bin/sidef $0 ${1+"$@"} "world"'
}
say "Hello, #{ARGV[0]}!"
- Output:
$ ./script.sf Hello, world! $ ./script.sf Sidef Hello, Sidef! $ sidef script.sf RosettaCode Hello, RosettaCode!
Smalltalk
"exec" "gst" "-f" "$0" "$0" "$@"
SQL PL
Based on the Postgres shebang, it works the same with IBM Db2.
--() { :; }; exec db2 -txf "$0"
get instance;
connect to sample;
select 'Hello' from sysibm.sysdummy1;
values current date;
Output:
$ ./myScript The current database manager instance is: db2inst1 Database Connection Information Database server = DB2/LINUXX8664 11.1.1 SQL authorization ID = DB2INST1 Local database alias = SAMPLE Hello 04/22/2018
The db2profile should be loaded before executing the 'db2' command (. ~db2inst1/sqllib/db2profile).
The options used in the example are: t - delimited by semi colon, x - Suppress printing of column headings, f - Read from input file. For other options, you can execute 'db2 ? options', and change the shebang.
Tcl
It is normal to use a line like this:
#!/usr/bin/env tclsh
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:
#!/bin/sh
# Next line is comment in Tcl, but not in sh... \
exec tclsh "$0" ${1+"$@"}
Additional complexity can be added so long as the lines for the shell are commented in a Tcl sense.
TXR
#!/bin/sh sed -n -e '4,$p' < "$0" | /usr/bin/txr -B - "$0" "$@" exit $? @(next :args) @(collect) @arg @(end)
Test run:
$ ./multilineshebang.txr arg[0]="./multilineshebang.txr" $ ./multilineshebang.txr 1 arg[0]="./multilineshebang.txr" arg[1]="1" $ ./multilineshebang.txr 1 2 3 arg[0]="./multilineshebang.txr" arg[1]="1" arg[2]="2" arg[3]="3" $
Wren
Wren doesn't support multiline shebangs as such. Anything after the first line is always interpreted as Wren code.
You can get around this by placing shell commands in a block comment after a single line shebang. So (ignoring the strange error message) the following works:
#!/bin/bash
/*
echo "Hello from bash"
/bin/wren Multiline_shebang.wren
exit
*/
System.print("Hello from Wren")
- Output:
$ chmod +x Multiline_shebang.wren $ ./Multiline_shebang.wren ./Multiline_shebang.wren: line 2: /bin: Is a directory Hello from bash Hello from Wren
However, we don't actually need a multiline shebang to get the script name as this is always passed automatically as the second command line argument when the Wren process is spawned, the first argument being the Wren executable itself. Moreover, if a single line shebang is used, the third argument will be the shell command used to execute the script.
#!/bin/wren Multiline_shebang_2.wren
import "os" for Process
var args = Process.allArguments
System.print("Executable : %(args[0])")
System.print("Script name : %(args[1])")
System.print("Shell command : %(args[2])")
if (args.count > 3) {
for (i in 3...args.count) System.print("Argument %(i-2) : %(args[i])")
}
- Output:
$ chmod +x Multiline_shebang_2.wren $ ./Multiline_shebang_2.wren one two three Executable : /bin/wren Script name : Multiline_shebang_2.wren Shell command : ./Multiline_shebang_2.wren Argument 1 : one Argument 2 : two Argument 3 : three
zkl
zkl has a variant of the here doc that means ignore the doc, as in "#if 0" but more so. But that doesn't mean a shell has to ignore it.
File foo.zkl (the .zkl extension is needed):
#!/bin/sh
#<<<#
echo "A shell script in a zkl program ($0)"
echo "Now run zkl <this file> with Hello World as args"
zkl $0 Hello World!
exit
#<<<#
println("The shell script says ",vm.arglist.concat(" "));
- Output:
$ ./foo.zkl A shell script in a zkl program (./foo.zkl) Now run zkl <this file> with Hello World as args The shell script says Hello World! $
- Draft Programming Tasks
- Basic language learning
- Ada
- C
- Clojure
- Common Lisp
- E
- Emacs Lisp
- Erlang
- F Sharp
- Factor
- Forth
- FreeBASIC
- Go
- Groovy
- Haskell
- J
- Jq
- Julia
- MATLAB
- Nim
- OCaml
- PARI/GP
- Perl
- Phix
- PicoLisp
- Pike
- PostgreSQL
- Python
- Racket
- Raku
- Ruby
- Scala
- Scheme
- Sidef
- Smalltalk
- SQL PL
- Tcl
- TXR
- Wren
- Zkl
- BASIC/Omit
- BBC BASIC/Omit
- Blast/Omit
- Brlcad/Omit
- GUISS/Omit
- Locomotive Basic/Omit
- Nemerle/Omit
- Openscad/Omit
- Z80A/Omit
- ZX Spectrum Basic/Omit