Native shebang: Difference between revisions

m
 
(35 intermediate revisions by 14 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:
<syntaxhighlight lang="text">#! /usr/local/bin/4th cxq
argn 1 ?do i args type space loop cr</syntaxhighlight>
 
=={{header|Free Pascal}}==
'''File: echo.sh'''
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.
<lang sh>#!/bin/sh
The program fulfills this task’s specifications, plus other goodies.
echo "$@"</lang>
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}}==
'''Usage:'''
In Go, single line comments can only begin with // and so we have to use the former in place of a normal shebang (#!) to achieve the same effect.
<pre>
./echo.sh Hello, world!
</pre>
{{out}}
<pre>
Hello, world!
</pre>
 
The 'go run' command compiles a .go source code file to a binary executable and then runs the latter automatically. The executable is placed in a temporary directory which is then deleted when the process ends.
===Using bash to script C===
{{works with|Bourne Again SHell}}
 
To cache the executable in the current directory, one would have to use 'go build' instead (replace the opening line with ///usr/bin/env go build echo.go; ./echo "$@"; exit).
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.
 
The following works fine on Ubuntu 16.04.
'''File: script_gcc.sh'''
<syntaxhighlight lang="go">///usr/bin/env go run echo.go "$@"; exit
<lang bash>#!/bin/bash
package main
 
import (
# Actual shebang when using bash:
"fmt"
#!/usr/local/bin/script_gcc.sh
"os"
)
 
func main() {
# Alternative shebang when using bash:
if len(os.Args) > 1 {
#!/bin/bash /usr/local/bin/script_gcc.sh
fmt.Println(os.Args[1])
}
}</syntaxhighlight>
 
# 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>
$ ./echo.go "Hello, world!"
Hello, world!
</pre>
 
 
=={{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 565 ⟶ 502:
 
'''Example 1:'''
<langsyntaxhighlight lang="sh">$ cat echo.foo
#!/usr/bin/env/jq -M -n -r -f
"Klaatu barada nikto!"</langsyntaxhighlight>
 
 
Line 581 ⟶ 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|PerlJulia}}==
usage: ./thisfile.jl "hello"
Perl is a script language. It's natural and easy to script native Perl code.
<syntaxhighlight lang="julia">#!/usr/local/bin/julia
 
# Put the Julia code below this line. It will be compiled and run.
'''File: echo.pl'''
<lang perl>#!/usr/bin/perl
print "@ARGV\n";
</lang>
 
Base.banner()
'''Usage:'''
println(ARGS)
 
</syntaxhighlight>{{out}}
<pre>
_
./echo.pl Hello, world!
_ _ _(_)_ | Documentation: https://docs.julialang.org
(_) | (_) (_) |
_ _ _| |_ __ _ | Type "?" for help, "]?" for Pkg help.
| | | | | | |/ _` | |
| | |_| | | | (_| | | 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}}==
OCaml can run in script mode or compiled (compiled to bytecode or native binary).
 
'''File: echo.ml'''
<syntaxhighlight lang="ocaml">#! /usr/bin/env ocaml
 
let () =
let argl = Array.to_list Sys.argv in
print_endline (String.concat " " (List.tl argl))</syntaxhighlight>
{{out}}
<pre>
$ chmod u+x echo.ml
$ ./echo.ml Hello, world!
Hello, world!
</pre>
But we have to remove the shebang if we want to compile the code, or we get an error:
=={{header|Perl 6}}==
<pre>
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.
$ ocamlc -c echo.ml
{{works with|Rakudo|2015-11-20}}
File "echo.ml", line 1, characters 0-2:
Error: Syntax error
</pre>
 
=={{header|Perl}}==
'''File: echo.p6'''
Perl is a script language. It's natural and easy to script native Perl code.
<lang perl6>#!/path/to/perl6
 
put @*ARGS;</lang>
'''File: echo.pl'''
<syntaxhighlight lang="perl">#!/usr/bin/perl
print "@ARGV\n";
</syntaxhighlight>
 
'''Usage:'''
<pre>
./echo.p6pl Hello, world!
</pre>
{{out}}
Line 621 ⟶ 628:
</pre>
 
=={{header|PythonPhix}}==
Phix is a hybrid interpreter/compiler, so a shebang adds little value anyway, however should the first
line of the main file start with #! it is ignored/skipped. The only difference between interpretation
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):
<syntaxhighlight lang="phix">#!/path/to/phix</syntaxhighlight>
You can also invoke the compiler directly as follows
<!--<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>
<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>
<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>
<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>
<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>
<!--</syntaxhighlight>-->
See also demo/capture_console.exw which redirects stdin/out/err while interpreting a child process.
 
=={{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 630 ⟶ 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 646 ⟶ 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 661 ⟶ 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 689 ⟶ 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
<syntaxhighlight lang="rexx">
#!/usr/local/bin/regina
/* Echo the command line argument */
say arg(1)
</syntaxhighlight>
 
===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.
<syntaxhighlight lang="rexx">
/* Echo the command line argument */
say arg(1)
</syntaxhighlight>
 
=={{header|Ruby}}==
Line 695 ⟶ 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 708 ⟶ 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 725 ⟶ 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>
 
=={{header|zkl}}==
This isn't something that is usually done with zkl as the compiler is fast enough (for scripts) to just run the source and let it get compiled and run. But, it can be done. Note: The binary still "links" against zkl (the VM) so the #! is required.
 
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
 
// This file: nativeShebang.zkl
// zkl --#! . -c nativeShebang -o.
// chmod a+x nativeShebang.z*
// ./nativeShebang.zsc
 
 
// If this [source] file is newer than the compiled version (or the
// compiled file doesn't exist), compile up a new version
 
runningName :=System.argv[1]; // argv==("zkl","nativeShebang.zkl|zsc")
srcName :=__FILE__;
compiledNameparts,path :=File.splitFileName(srcNamerunningName),parts[0,-12].concat() +or ".zsc";
srcName :=parts[0,-1].concat() + ".zkl";
compiledName:=parts[0,-1].concat() + ".zsc";
if(not File.exists(compiledName) or
File.info(srcName)[2] > File.info(compiledName)[2]){ // compare modifed dates
System.cmd("zkl --#! . -c %s -o.%s --exit".fmt(srcName,path));
System.cmd("chmod a+x %s".fmt(compiledName));
}
 
println("Hello world!");</lang>
////////////// the script:
println("Hello world!");</syntaxhighlight>
{{out}}
<pre>
#run the source in the usual manner to generate a binary
#could use ./nativeShebang.zkl if chmod'd it
$ zkl nativeShebang.zkl
Compiled Class(nativeShebang) (0.0 seconds, ??? lines/sec)
Line 782 ⟶ 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