Native shebang: Difference between revisions

m
(Added perl script.)
 
(43 intermediate revisions by 18 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 227 ⟶ 237:
</pre>
 
===2nd version. Pure C, no extra bash script===
=={{header|UNIX Shell}}==
'''File: script_gcc.c'''
===Using sh to script sh===
<syntaxhighlight lang="c">/*
In strictly shell this is natural, native and easy:
* rosettacode.org: Native shebang
*
* Copyright 2015, Jim Fougeron. Code placed in public domain. If you
* use this, please provide attribution to author. Code originally came
* from the code found on rosettacode.org/wiki/Native_shebang, however
* the code was about 80% rewritten. But the logic of the compile()
* function still strongly is based upon original code, and is a key
* part of the file.
*
* Native C language shebang scripting. Build this program to /usr/local/bin
* using:
* gcc -o/usr/local/bin/script_gcc script_gcc.c
*
* The name of the executable: "script_gcc" IS critical. It is used in knowing
* that we have have found the proper shebang file when parsing commandline
*
* the actual shebang for executable C source scripts is:
 
#!/usr/local/bin/script_gcc [extra compile/link options]
'''File: echo.sh'''
<lang sh>#!/bin/sh
echo "$@"</lang>
 
* If there additional lib's needed by your source file, then add the proper
'''Usage:'''
* params to the shebang line. So for instance if gmp, openssl, and zlib
<pre>
* were needed (and an additional include path), you would use this shebang:
./echo.sh Hello, world!
</pre>
{{out}}
<pre>
Hello, world!
</pre>
 
#!/usr/local/bin/script_gcc -lgmp -lssl -lcrypto -lz -I/usr/local/include
===Using bash to script C===
{{works with|Bourne Again SHell}}
 
* NOTE, we leak strdup calls, but they are 1 time leaks, and this process
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.
* will simply exec another process, so we ignore them.
*/
 
#include <errno.h>
'''File: script_gcc.sh'''
#include <libgen.h>
<lang bash>#!/bin/bash
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
 
#define shebangNAME "script_gcc"
# Actual shebang when using bash:
#define CC "gcc"
#!/usr/local/bin/script_gcc.sh
#define CC_OPTS "-lm -x c"
#define IEXT ".c"
#define OEXT ".out"
 
/* return time of file modification. If file does not exit, return 0
# Alternative shebang when using bash:
* so that if we compare, it will always be older, and will be built */
#!/bin/bash /usr/local/bin/script_gcc.sh
time_t modtime(const char *filename) {
struct stat st;
 
if(stat(filename, &st) != EXIT_SUCCESS)
# CACHE=No # to turn off caching...
return 0;
return st.st_mtime;
}
/* join a pair of strings */
char *sjoin(const char *s1, const char *s2){
char buf[BUFSIZ];
 
if (!s1) s1=""; if (!s2) s2="";
# Note: this shell should be re-written in actual C! :-)
snprintf(buf, sizeof(buf), "%s%s", s1, s2);
return strdup(buf);
}
/* compiles the original script file. It skips the first line (the shebang)
* and compiles using "gcc .... -x c -" which avoids having to write a temp
* source file (minus the shebang), we instead pipe source to gcc */
int compile(const char *srcpath, const char *binpath, const char *ex_comp_opts) {
char buf[BUFSIZ];
FILE *fsrc, *fcmp;
 
sprintf(buf, "%s %s %s -o %s -", CC, CC_OPTS, ex_comp_opts, binpath);
DIALECT=c # or cpp
fsrc=fopen(srcpath, "r");
CC="gcc"
if (!fsrc) return -1;
COPTS="-lm -x $DIALECT"
fcmp=popen(buf, "w"); /* open up our gcc pipe to send it source */
IEXT=.$DIALECT
if (!fcmp) { fclose(fsrc); return -1; }
OEXT=.out
 
/* skip shebang line, then compile rest of the file. */
ENOENT=2
fgets(buf, sizeof(buf), fsrc);
fgets(buf, sizeof(buf), fsrc);
while (!feof(fsrc)) {
fputs(buf, fcmp); /* compile this line of source with gcc */
fgets(buf, sizeof(buf), fsrc);
}
fclose(fsrc);
return pclose(fcmp);
}
 
/* tries to open the file 'argv0'. If we can open that file we read first line
srcpath="$1"; shift # => "$@"
* and make SURE it is a script_gcc file. If it is a script_gcc file, we
#basename="$(basename "$srcpath" ."$DIALECT")"
* look for any extra params for the compiler (params to the shebang line)
basename="$(basename "$srcpath")"
* and if we find them, they are returned in ex_comp_opts.
* return 0 if this is NOT a shebang file, return 1 if it IS the shebang file.
*/
int load_shebangline(const char *argv0, char **ex_comp_opts) {
char opt[BUFSIZ], *cp;
FILE *in = fopen(argv0, "r");
 
if (!in) return 0;
# Warning: current dir "." is in path, AND */tmp directories are common/shared
fgets(opt, sizeof(opt), in);
paths="$(dirname "$srcpath")
fclose(in);
$HOME/bin
/* ok, we found a readable file, but IS it our shebang file? */
/usr/local/bin
strtok(opt, "\r\n");
.
if (strncmp(opt, "#!", 2) || !strstr(opt, shebangNAME))
$HOME/tmp
return 0; /* nope, keep looking */
$HOME
cp = strstr(opt, shebangNAME)+strlen(shebangNAME);
$HOME/Desktop"
if (*cp) /* capture compiler extra params, if any */
#/tmp
*ex_comp_opts = strdup(cp);
return 1;
}
 
/* NOTE, the argv[] array is different than 'normal' C programs. argv[0] is
while read dirnamew; do
* the shebang exe file. then argv[1] ... argv[p] are the params that follow
[ -w "$dirnamew" ] && break
* the shebang script name (from line1 of the script file). NOTE, some systems
done << end_here_is
* (Linux, cygwin), will pack all of these options into argv[1] with spaces.
$paths
* There is NO 'standard' on exactly what the layout it of these shebang params
end_here_is
* may be, we only know that there will be 0 or more params BEFORE the script
* name (which is the argv[0] we normally 'expect). Then argv[p+1] is the name
* of script being run. NOTE if there are no shebang args, argv[1] will be
* the script file name. The script file name is our expected argv[0], and
* all the params following that are the normal argv[1]...argv[n] we expect.
*/
int main(int argc, char *const argv[]) {
int i;
char exec_path[BUFSIZ], *argv0_basename, *ex_comp_opts=0, **dir,
*paths[] = {
NULL, /* paths[0] will be filled in later, to dir of the script */
"/usr/local/bin",
sjoin(getenv("HOME"), "/bin"),
sjoin(getenv("HOME"), "/tmp"),
getenv("HOME"),
sjoin(getenv("HOME"), "/Desktop"),
/* . and /tmp removed due to security concerns
".",
"/tmp", */
NULL
};
 
/* parse args, looking for the one that is the script. This would have been argv[0] if not exec'd as a shebang */
compile(){
for (i = 1; i < argc; ++i) {
sed -n '2,$p' "$srcpath" | "$CC" $COPTS -o "$binpath" -
if (load_shebangline(argv[1], &ex_comp_opts)) {
argc -= i;
i = 0;
break;
}
++argv;
}
if (i)
return !fprintf(stderr, "could not locate proper %s shebang file!!\n", shebangNAME) | ENOENT;
++argv;
/* found it. Now argv[0] is the 'script' name, and rest of argv[] is params to the script */
argv0_basename = basename(strdup(argv[0]));
paths[0] = dirname(strdup(argv[0]));
/* find a cached version of the script, and if we find it, run it */
for(dir = paths; *dir; dir++) {
snprintf(exec_path, sizeof(exec_path), "%s/%s%s", *dir, argv0_basename, OEXT);
if(modtime(exec_path) >= modtime(argv[0]))
execvp(exec_path, argv); /* found a newer cached compiled file. Run it */
}
/* no cached file, or script is newer. So find a writeable dir */
for(dir = paths; *dir; dir++) {
if(!access(*dir, W_OK))
break;
}
if (!*dir)
return !fprintf(stderr, "No writeable directory for compile of the script %s\n", argv[0]) | EACCES;
/* compile and exec the result from our C script source file */
snprintf(exec_path, sizeof(exec_path), "%s/%s%s", *dir, argv0_basename, OEXT);
if(!compile(argv[0], exec_path, ex_comp_opts))
execvp(exec_path, argv);
return !fprintf(stderr, "%s : executable not available\n", exec_path) | ENOENT;
}
</syntaxhighlight>
 
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'''
<langsyntaxhighlight lang="c">#!/usr/local/bin/script_gcc.sh
/*
* note, any additional libs or include paths would have params added after
* the script_gcc parts of the shebang line, such as:
* #!/usr/local/bin/script_gcc -lgmp -I/usr/local/include/gmp5
*/
#include <stdio.h>
#include <string.h>
Line 328 ⟶ 431:
putchar('\n');
exit(EXIT_SUCCESS);
}</langsyntaxhighlight>
 
'''Test Execution:'''
Line 339 ⟶ 442:
</pre>
 
=={{header|Forth}}==
Such functionality can be added easily by the following definition:
<syntaxhighlight lang="text">: #! [COMPILE] \ ; immediate</syntaxhighlight>
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}}==
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}}==
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.
 
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.
 
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).
 
The following works fine on Ubuntu 16.04.
<syntaxhighlight lang="go">///usr/bin/env go run echo.go "$@"; exit
package main
 
import (
"fmt"
"os"
)
 
func main() {
if len(os.Args) > 1 {
fmt.Println(os.Args[1])
}
}</syntaxhighlight>
 
{{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:
 
<syntaxhighlight lang="j">#!/usr/local/bin/ijconsole
echo each ARGV</syntaxhighlight>
 
=={{header|jq}}==
{{works with|jq|1.4}}
 
jq can be invoked on the shebang line, e.g. as
Line 349 ⟶ 499:
or
 
#!/usr/bin/env/ jq -M -n -f
 
'''Example 1:'''
<langsyntaxhighlight lang="sh">$ cat echo.foo
#!/usr/bin/env/jq -M -n -r -f
"Klaatu barada nikto!"</langsyntaxhighlight>
 
 
Line 368 ⟶ 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"
<syntaxhighlight lang="julia">#!/usr/local/bin/julia
 
# Put the Julia code below this line. It will be compiled and run.
 
Base.banner()
println(ARGS)
 
</syntaxhighlight>{{out}}
<pre>
_
_ _ _(_)_ | 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:
<pre>
$ ocamlc -c echo.ml
File "echo.ml", line 1, characters 0-2:
Error: Syntax error
</pre>
 
=={{header|Perl}}==
Perl is a script language. It's natural and easy to script native Perl code.
===Using perl to script perl===
Perl is a script language, so it is natural, native and easy:
 
'''File: echo.pl'''
<langsyntaxhighlight lang="perl">#!/usr/bin/perl
print "@ARGV\n";
</syntaxhighlight>
</lang>
 
'''Usage:'''
Line 393 ⟶ 628:
</pre>
 
=={{header|Phix}}==
 
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 404 ⟶ 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 420 ⟶ 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 435 ⟶ 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 463 ⟶ 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}}==
Ruby does not compile to a binary, thankfully.
 
=={{header|Sidef}}==
Sidef is a scripting language and does not compile to a binary.
<syntaxhighlight lang="ruby">#!/usr/bin/sidef
say ARGV.join(" ")</syntaxhighlight>
 
{{out}}
<pre>
$ ./echo.sf Hello, World!
Hello, World!
</pre>
 
=={{header|Swift}}==
Line 471 ⟶ 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 489 ⟶ 782:
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.
<syntaxhighlight lang="zkl">#!/home/craigd/Bin/zkl
// This file: nativeShebang.zkl, compiles to nativeShebang.zsc
// 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")
parts,path :=File.splitFileName(runningName),parts[0,2].concat() or ".";
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));
}
 
////////////// 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)
Wrote Class(nativeShebang) to ./nativeShebang.zsc
Hello world!
 
#eyeball the binary
$ zkl hexDump nativeShebang.zsc
0: 23 21 2f 68 6f 6d 65 2f | 63 72 61 69 67 64 2f 42 #!/home/craigd/B
16: 69 6e 2f 7a 6b 6c 0a 7a | 6b 44 00 00 28 31 2e 31 in/zkl.zkD..(1.1
32: 00 5a 4b 4c 20 53 65 72 | 69 61 6c 69 7a 65 64 20 .ZKL Serialized
48: 43 6c 61 73 73 00 6e 61 | 74 69 76 65 53 68 65 62 Class.nativeSheb
64: 61 6e 67 00 00 02 00 00 | 34 2b 61 74 74 72 69 62 ang.....4+attrib
80: 75 74 65 73 3a 73 74 61 | 74 69 63 20 63 72 65 61 utes:static crea
96: 74 65 52 65 74 75 72 6e | 73 53 65 6c 66 00 6e 61 teReturnsSelf.na
112: 74 69 76 65 53 68 65 62 | 61 6e 67 00 00 00 01 00 tiveShebang.....
...
 
#run the binary
$ ./nativeShebang.zsc
Hello world!
 
#see if update works
$ touch ./nativeShebang.zkl
$ ./nativeShebang.zsc
Compiled Class(nativeShebang) (0.0 seconds, ??? lines/sec)
Wrote Class(nativeShebang) to ./nativeShebang.zsc
Hello world!
#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