Native shebang: Difference between revisions

m
 
(25 intermediate revisions by 11 users not shown)
Line 55:
Also note that this ".so" will only be generated if the ".a68" source file
has been touched.
'''File: echo.a68'''<langsyntaxhighlight lang="algol68">#!/usr/bin/a68g --script #
# -*- coding: utf-8 -*- #
 
STRING ofs := "";
FOR i FROM 4 TO argc DO print((ofs, argv(i))); ofs:=" " OD</langsyntaxhighlight>
'''Test Execution:'''
<pre>
Line 68:
Hello, world!
</pre>
 
=={{header|Arturo}}==
Arturo is a scripting language and does not compile to a binary.
<syntaxhighlight lang="rebol">#!/usr/bin/env arturo
print "Hello from Arturo!"</syntaxhighlight>
 
{{out}}
 
<pre>$> ./native_shebang.art
Hello from Arturo!</pre>
 
=={{header|C}}==
Line 76 ⟶ 86:
 
'''File: script_gcc.c'''
<langsyntaxhighlight lang="c">#!/usr/local/bin/script_gcc.sh
/* Optional: this C code initially is-being/can-be boot strapped (compiled) using bash script_gcc.sh */
#include <errno.h>
Line 200 ⟶ 210:
perror(STRCAT(binpath, ": executable not available", ENDCAT));
exit(errno);
}</langsyntaxhighlight>
 
'''Test Source File: echo.c'''
<langsyntaxhighlight lang="c">#!/usr/local/bin/script_gcc.c
#include <stdio.h>
#include <string.h>
Line 216 ⟶ 226:
putchar('\n');
exit(EXIT_SUCCESS);
}</langsyntaxhighlight>
 
'''Test Execution:'''
Line 228 ⟶ 238:
 
===2nd version. Pure C, no extra bash script===
 
'''File: script_gcc.c'''
<langsyntaxhighlight lang="c">/*
* rosettacode.org: Native shebang
*
Line 401 ⟶ 410:
return !fprintf(stderr, "%s : executable not available\n", exec_path) | ENOENT;
}
</syntaxhighlight>
</lang>
 
'''Test Source File: echo.c'''
<langsyntaxhighlight lang="c">#!/usr/local/bin/script_gcc
/*
* note, any additional libs or include paths would have params added after
Line 422 ⟶ 431:
putchar('\n');
exit(EXIT_SUCCESS);
}</langsyntaxhighlight>
 
'''Test Execution:'''
Line 433 ⟶ 442:
</pre>
 
=={{header|UNIX ShellForth}}==
Such functionality can be added easily by the following definition:
===Using sh to script sh===
<syntaxhighlight lang="text">: #! [COMPILE] \ ; immediate</syntaxhighlight>
In strictly shell this is natural, native and easy:
Some Forth compilers - like 4tH or Gforth - support this functionality out of the box.
 
This example program works as advertised:
'''File: echo.sh'''
<syntaxhighlight lang="text">#! /usr/local/bin/4th cxq
<lang sh>#!/bin/sh
argn 1 ?do i args type space loop cr</syntaxhighlight>
echo "$@"</lang>
 
'''Usage:'''
<pre>
./echo.sh Hello, world!
</pre>
{{out}}
<pre>
Hello, world!
</pre>
 
===Using bash to script C===
{{works with|Bourne Again SHell}}
 
Note: this '''Native shebang''' task does not exactly apply to [[bash]] because bash is interpretive, but as a skeleton template the following script is an example of how compiled languages can implement the shebang. Also: this bash code can be used to ''automatically'' compile the C code in /usr/local/bin/script_gcc.c above.
 
'''File: script_gcc.sh'''
<lang bash>#!/bin/bash
 
# Actual shebang when using bash:
#!/usr/local/bin/script_gcc.sh
 
# Alternative shebang when using bash:
#!/bin/bash /usr/local/bin/script_gcc.sh
 
# CACHE=No # to turn off caching...
 
# Note: this shell should be re-written in actual C! :-)
 
DIALECT=c # or cpp
CC="gcc"
COPTS="-lm -x $DIALECT"
IEXT=.$DIALECT
OEXT=.out
 
ENOENT=2
 
srcpath="$1"; shift # => "$@"
#basename="$(basename "$srcpath" ."$DIALECT")"
basename="$(basename "$srcpath")"
 
# Warning: current dir "." is in path, AND */tmp directories are common/shared
paths="$(dirname "$srcpath")
$HOME/bin
/usr/local/bin
.
$HOME/tmp
$HOME
$HOME/Desktop"
#/tmp
 
while read dirnamew; do
[ -w "$dirnamew" ] && break
done << end_here_is
$paths
end_here_is
 
compile(){
sed -n '2,$p' "$srcpath" | "$CC" $COPTS -o "$binpath" -
}
 
if [ "'$CACHE'" = "'No'" ]; then
binpath="$dirnamew/$basename-v$$$OEXT"
if compile; then
( sleep 0.1; exec rm "$binpath" ) & exec "$binpath" "$@"
fi
else
while read dirnamex; do
binpath="$dirnamex/$basename$OEXT"
if [ -x "$binpath" -a "$binpath" -nt "$srcpath" ];
then exec "$binpath" "$@"; fi
done << end_here_is
$paths
end_here_is
 
binpath="$dirnamew/$basename$OEXT"
if compile; then exec "$binpath" "$@"; fi
 
echo "$binpath: executable not available" 1>&2
exit $ENOENT
fi</lang>
'''Test Source File: echo.c'''
<lang c>#!/usr/local/bin/script_gcc.sh
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
 
int main(int argc, char **argv, char **envp){
char ofs = '\0';
for(argv++; *argv; argv++){
if(ofs)putchar(ofs); else ofs=' ';
fwrite(*argv, strlen(*argv), 1, stdout);
}
putchar('\n');
exit(EXIT_SUCCESS);
}</lang>
 
'''Test Execution:'''
<pre>
$ ./echo.c Hello, world!
</pre>
{{out}}
<pre>
Hello, world!
</pre>
 
=={{header|Free Pascal}}==
Since FPC (FreePascal compiler) version 2.6.0 the distribution – e.g. the Debian or FreeBSD packages <tt>fpc-utils</tt> – come with the program <tt>instantfpc(1)</tt>, or <tt>ifpc(1)</tt> for short.
The program fulfills this task’s specifications, plus other goodies.
The sources are available in [https://gitlab.com/freepascal.org/fpc/source/-/blob/release_3_2_0/utils/instantfpc/instantfpc.pas <tt>trunk/utils/instantfpc/instantfpc.pas</tt>] and are not repeated here.
See the [https://wiki.freepascal.org/InstantFPC FreePascal wiki for <tt>ifpc</tt> usage].
 
=={{header|Go}}==
Line 554 ⟶ 464:
 
The following works fine on Ubuntu 16.04.
<langsyntaxhighlight lang="go">///usr/bin/env go run echo.go "$@"; exit
package main
 
Line 566 ⟶ 476:
fmt.Println(os.Args[1])
}
}</langsyntaxhighlight>
 
{{out}}
Line 575 ⟶ 485:
 
=={{header|J}}==
 
As no compiling versions of J are currently available, the binaries are trivially empty and we shall store them in the empty path. We shall use /usr/local/bin/ijconsole (which was compiled using a C compiler) as the J interpreter, and <code>echo each ARGV</code> as our sample code:
 
<langsyntaxhighlight Jlang="j">#!/usr/local/bin/ijconsole
echo each ARGV</langsyntaxhighlight>
 
=={{header|jq}}==
{{works with|jq|1.4}}
 
jq can be invoked on the shebang line, e.g. as
Line 593 ⟶ 502:
 
'''Example 1:'''
<langsyntaxhighlight lang="sh">$ cat echo.foo
#!/usr/bin/env/jq -M -n -r -f
"Klaatu barada nikto!"</langsyntaxhighlight>
 
 
Line 609 ⟶ 518:
 
'''Example 2:'''
<langsyntaxhighlight lang="sh">$ cat echo.foo
#!/usr/bin/env/jq -M -n -r -f
$x</langsyntaxhighlight>
{{out}}
<langsyntaxhighlight lang="sh">$ ./echo.foo --arg x "Hello, world!"
Hello, world!</langsyntaxhighlight>
 
 
=={{header|Julia}}==
usage: ./thisfile.jl "hello"
<lang julia>#!/usr/local/bin/julia
<syntaxhighlight lang="julia">#!/usr/local/bin/julia
 
# Put the Julia code below this line. It will be compiled and run.
 
Base.banner()
println(ARGS)
 
</langsyntaxhighlight>{{out}}
<pre>
_
Line 633 ⟶ 543:
| | |_| | | | (_| | | Version 1.1.1 (2019-05-16)
_/ |\__'_|_|_|\__'_| | Official https://julialang.org/ release
|__/ |
hello |
</pre>
 
=={{header|langur}}==
Langur uses a hash mark to start single line comments, so a shebang is not a problem, as the compiler will ignore it.
 
'''File: echo.langur'''
<syntaxhighlight lang="langur">#!/usr/bin/langur
writeln join " ", _args</syntaxhighlight>
 
'''Usage:'''
<pre>./echo.langur hello, people</pre>
 
{{out}}
<pre>hello, people</pre>
 
=={{header|Nim}}==
===Using env===
Uses env -S to split up the commandline parameters,which is maybe cheating
but apart from that housekeeping this ticks all the boxes:
* it compiles the source code to an executable, if and only if it has changed
* it then runs that executable with the supplied arguments
 
'''File: nativeshebang.nim'''
<syntaxhighlight lang="nim">#!/usr/bin/env -S nim c -r --hints:off
import os,strutils
echo commandLineParams().join(" ")</syntaxhighlight>
'''Usage:'''
<pre>./nativeshebang.nim hello, world</pre>
{{out}}
<pre>hello, world</pre>
===Using a nim.cfg and/or nim r===
Alternatively, accept all the compiler messages, or create a nim.cfg that silences them:
 
'''File: nim.cfg'''
<syntaxhighlight lang="nim">--hints:off</syntaxhighlight>
'''File: nativeshebang2.nims'''
<syntaxhighlight lang="nim">#!nim r
import os,strutils
echo commandLineParams().join(" ")</syntaxhighlight>
'''Usage:'''
<pre>./nativeshebang2.nim hello, world</pre>
{{out}}
<pre>hello, world</pre>
 
=={{header|OCaml}}==
Line 640 ⟶ 593:
 
'''File: echo.ml'''
<langsyntaxhighlight lang="ocaml">#! /usr/bin/env ocaml
 
let () =
let argl = Array.to_list Sys.argv in
print_endline (String.concat " " (List.tl argl))</langsyntaxhighlight>
{{out}}
<pre>
Line 662 ⟶ 615:
 
'''File: echo.pl'''
<langsyntaxhighlight lang="perl">#!/usr/bin/perl
print "@ARGV\n";
</syntaxhighlight>
</lang>
 
'''Usage:'''
Line 675 ⟶ 628:
</pre>
 
=={{header|Perl 6Phix}}==
Phix is a hybrid interpreter/compiler, so a shebang adds little value anyway, however should the first
Perl 6 is not installed by default on most systems and does not have a default install directory, so the path will vary by system.
line of the main file start with #! it is ignored/skipped. The only difference between interpretation
{{works with|Rakudo|2015-11-20}}
and compilation, apart from the executable file, is a -c flag on the command line, which I recommend
 
omitting unless it proves helpful or necessary. Example (quietly ignored by pwa/p2js, and Phix in general):
'''File: echo.p6'''
<langsyntaxhighlight perl6lang="phix">#!/path/to/perl6phix</syntaxhighlight>
You can also invoke the compiler directly as follows
put @*ARGS;</lang>
<!--<syntaxhighlight lang="phix">(phixonline)-->
 
<span style="color: #008080;">without</span> <span style="color: #008080;">js</span> <span style="color: #000080;font-style:italic;">-- (system_exec)</span>
'''Usage:'''
<span style="color: #004080;">string</span> <span style="color: #000000;">sourcefile</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">"test.exw"</span><span style="color: #0000FF;">,</span>
<pre>
<span style="color: #000000;">interpreter</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">get_interpreter</span><span style="color: #0000FF;">(</span><span style="color: #004600;">true</span><span style="color: #0000FF;">),</span>
./echo.p6 Hello, world!
<span style="color: #000000;">cmd</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">sprintf</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"%s %s"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">interpreter</span><span style="color: #0000FF;">,</span><span style="color: #000000;">sourcefile</span><span style="color: #0000FF;">})</span>
</pre>
<span style="color: #004080;">integer</span> <span style="color: #000000;">res</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">system_exec</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cmd</span><span style="color: #0000FF;">)</span>
{{out}}
<!--</syntaxhighlight>-->
<pre>
See also demo/capture_console.exw which redirects stdin/out/err while interpreting a child process.
Hello, world!
</pre>
 
=={{header|Python}}==
 
Extract: "If you need to create a .pyc file for a module that is not imported, you can use the py_compile and compileall modules. The py_compile module can manually compile any module. One way is to use the py_compile.compile function in that module interactively:[http://effbot.org/pyfaq/how-do-i-create-a-pyc-file.htm]:"
<pre>
Line 701 ⟶ 652:
 
'''File: echo.py'''
<langsyntaxhighlight lang="python">#!/path/to/python
# Although `#!/usr/bin/env python` may be better if the path to python can change
 
import sys
print " ".join(sys.argv[1:])</langsyntaxhighlight>
 
'''Usage:'''
Line 717 ⟶ 668:
 
=={{header|Racket}}==
 
Racket has [http://docs.racket-lang.org/raco/index.html?q=raco <tt>raco: Racket Command Line Tools</tt>]
which can be used to compile to bytecode or compile to standalone executables (along with a whole load of
Line 732 ⟶ 682:
 
File <tt>native-shebang.rkt</tt> contains the following:
<langsyntaxhighlight lang="racket">#! /usr/local/racket-6.1/bin/racket
#lang racket
(displayln "hello")</langsyntaxhighlight>
 
My directory contains only this:
Line 760 ⟶ 710:
hello</pre>
(although it's hard to prove)
 
=={{header|Raku}}==
(formerly Perl 6)
 
Raku is not installed by default on most systems and does not have a default install directory, so the path will vary by system.
{{works with|Rakudo|2020.02}}
 
'''File: echo.p6'''
<syntaxhighlight lang="raku" line>#!/path/to/raku
put @*ARGS;</syntaxhighlight>
 
'''Usage:'''
<pre>
./echo.p6 Hello, world!
</pre>
{{out}}
<pre>
Hello, world!
</pre>
 
=={{header|REXX}}==
===Unix shebang===
Using e.g. Regina open source REXX interpreter
<langsyntaxhighlight lang="rexx">
#!/usr/local/bin/regina
/* Echo the command line argument */
say arg(1)
</syntaxhighlight>
</lang>
 
===ARexx===
Under AmigaOS, the obligatory REXX starting comment /* is recognised as a shebang of its own, automatically causing the file to be parsed by ARexx as long as the file's script flag is set.
<langsyntaxhighlight lang="rexx">
/* Echo the command line argument */
say arg(1)
</syntaxhighlight>
</lang>
 
=={{header|Ruby}}==
Line 782 ⟶ 751:
=={{header|Sidef}}==
Sidef is a scripting language and does not compile to a binary.
<langsyntaxhighlight lang="ruby">#!/usr/bin/sidef
say ARGV.join(" ")</langsyntaxhighlight>
 
{{out}}
Line 795 ⟶ 764:
 
'''File: echo.swift'''
<langsyntaxhighlight lang="swift">#!/usr/bin/swift
 
import Foundation
 
print(Process.arguments[1..<Process.arguments.count].joinWithSeparator(" "))
</syntaxhighlight>
</lang>
 
'''Usage:'''
 
<langsyntaxhighlight lang="bash">
./echo.swift Hello, world!
</syntaxhighlight>
</lang>
 
{{Out}}
Line 812 ⟶ 781:
<pre>
Hello, world!
</pre>
 
=={{header|UNIX Shell}}==
===Using sh to script sh===
In strictly shell this is natural, native and easy:
 
'''File: echo.sh'''
<syntaxhighlight lang="sh">#!/bin/sh
echo "$@"</syntaxhighlight>
 
'''Usage:'''
<pre>
./echo.sh Hello, world!
</pre>
{{out}}
<pre>
Hello, world!
</pre>
 
===Using bash to script C===
{{works with|Bourne Again SHell}}
 
Note: this '''Native shebang''' task does not exactly apply to [[bash]] because bash is interpretive, but as a skeleton template the following script is an example of how compiled languages can implement the shebang. Also: this bash code can be used to ''automatically'' compile the C code in /usr/local/bin/script_gcc.c above.
 
'''File: script_gcc.sh'''
<syntaxhighlight lang="bash">#!/bin/bash
 
# Actual shebang when using bash:
#!/usr/local/bin/script_gcc.sh
 
# Alternative shebang when using bash:
#!/bin/bash /usr/local/bin/script_gcc.sh
 
# CACHE=No # to turn off caching...
 
# Note: this shell should be re-written in actual C! :-)
 
DIALECT=c # or cpp
CC="gcc"
COPTS="-lm -x $DIALECT"
IEXT=.$DIALECT
OEXT=.out
 
ENOENT=2
 
srcpath="$1"; shift # => "$@"
#basename="$(basename "$srcpath" ."$DIALECT")"
basename="$(basename "$srcpath")"
 
# Warning: current dir "." is in path, AND */tmp directories are common/shared
paths="$(dirname "$srcpath")
$HOME/bin
/usr/local/bin
.
$HOME/tmp
$HOME
$HOME/Desktop"
#/tmp
 
while read dirnamew; do
[ -w "$dirnamew" ] && break
done << end_here_is
$paths
end_here_is
 
compile(){
sed -n '2,$p' "$srcpath" | "$CC" $COPTS -o "$binpath" -
}
 
if [ "'$CACHE'" = "'No'" ]; then
binpath="$dirnamew/$basename-v$$$OEXT"
if compile; then
( sleep 0.1; exec rm "$binpath" ) & exec "$binpath" "$@"
fi
else
while read dirnamex; do
binpath="$dirnamex/$basename$OEXT"
if [ -x "$binpath" -a "$binpath" -nt "$srcpath" ];
then exec "$binpath" "$@"; fi
done << end_here_is
$paths
end_here_is
 
binpath="$dirnamew/$basename$OEXT"
if compile; then exec "$binpath" "$@"; fi
 
echo "$binpath: executable not available" 1>&2
exit $ENOENT
fi</syntaxhighlight>
'''Test Source File: echo.c'''
<syntaxhighlight lang="c">#!/usr/local/bin/script_gcc.sh
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
 
int main(int argc, char **argv, char **envp){
char ofs = '\0';
for(argv++; *argv; argv++){
if(ofs)putchar(ofs); else ofs=' ';
fwrite(*argv, strlen(*argv), 1, stdout);
}
putchar('\n');
exit(EXIT_SUCCESS);
}</syntaxhighlight>
 
'''Test Execution:'''
<pre>
$ ./echo.c Hello, world!
</pre>
{{out}}
<pre>
Hello, world!
</pre>
 
=={{header|V (Vlang)}}==
<syntaxhighlight lang="Vlang">
$ cat file.v
#!/usr/local/bin/v run
println('hello')
 
$ chmod 755 file.v
$ ./file.v
============ running ./file ============
hello
</syntaxhighlight>
V also knows to compile & run .vsh files immediately, so you do not need a separate step to compile them.
 
An example deploy.vsh:
<syntaxhighlight lang="Vlang">
#!/usr/bin/env -S v
 
// Note: The shebang line above, associates the .vsh file to V on Unix-like systems,
// so it can be run just by specifying the path to the .vsh file...
</syntaxhighlight>
 
=={{header|Wren}}==
Normally, Process.arguments[0] would return the (first) command line argument but here we need to use Process.arguments[1] because the first argument passed to Wren's command line interpreter is ''./native_shebang.wren''.
<syntaxhighlight lang="wren">#!/bin/wren native_shebang.wren
import "os" for Process
System.print(Process.arguments[1])</syntaxhighlight>
 
{{out}}
<pre>
$ chmod +x native_shebang.wren
$ ./native_shebang.wren "Hello world!"
Hello world!
</pre>
 
Line 818 ⟶ 933:
 
Since the #! parsing is done by a compiler front end and was designed to be used from the command line, we'll do that by forking zkl to compile the source if it is newer than the binary.
<langsyntaxhighlight lang="zkl">#!/home/craigd/Bin/zkl
// This file: nativeShebang.zkl, compiles to nativeShebang.zsc
// zkl --#! . -c nativeShebang -o.
Line 838 ⟶ 953:
 
////////////// the script:
println("Hello world!");</langsyntaxhighlight>
{{out}}
<pre>
Line 872 ⟶ 987:
#yep, new binary generated
</pre>
 
{{omit from|6502 Assembly|There's no real way to do this except maybe by loading a file containing code and then JSR to its memory location.}}
{{omit from|68000 Assembly|See above.}}
{{omit from|8080 Assembly|See above.}}
{{omit from|8086 Assembly|See above.}}
{{omit from|ARM Assembly|See above.}}
{{omit from|Z80 Assembly|See above.}}
885

edits