Anstelle von myprg
auf magische Weise erkennen, ob es in einem Shebang verwendet wird, warum machen Sie das nicht explizit, indem Sie ein Befehlszeilen-Flag verwenden (wie -f
), um ihm eine Datei als Skript zu übergeben?
Aus Ihrem Beispiel in den Kommentaren:
In dem theoretischen Berechnungsbeispiel oben. calc PI + 1
sollte 4.14159 zurückgeben... Jetzt würde das Hinzufügen der Unterstützung für den Shebang (d. h. ein Dateiname als erster Parameter) die in der Datei enthaltene Berechnung zurückgeben.
Machen Sie calc
Nehmen Sie eine Skriptdatei durch -f
und erstellen Sie dann Skripte mit:
#!/usr/local/bin/calc -f
$1 + 1
Nehmen wir an, Sie nennen diese Datei addone.calc
und ausführbar machen. Dann können Sie es aufrufen mit:
$ ./addone.calc PI
4.141592...
Dieser Aufruf wird in einen Aufruf von /usr/local/bin/calc -f ./addone.calc PI
übersetzt , also ist es ziemlich klar, welches Argument eine Skriptdatei und welches ein Parameter für das Skript ist.
Dies ist ähnlich wie bei awk
und sed
verhält.
Ein ähnlicher (aber entgegengesetzter) Ansatz ist calc
Nehmen Sie standardmäßig ein Skriptdateiargument (was seine Verwendung mit einem Shebang vereinfacht), fügen Sie jedoch ein Befehlszeilen-Flag hinzu, um es mit einem Ausdruck aus einem Argument zu verwenden. Dies ist ähnlich wie bei sh -c '...'
funktioniert.
Das eigentliche Problem ist die Art und Weise, wie Sie die Befehlszeilensyntax von <mypgm>
entworfen haben . Anstatt zu versuchen, zwei Möglichkeiten zur Interpretation seiner Argumente zu unterstützen, bieten Sie stattdessen zwei Möglichkeiten an, es aufzurufen.
Shebang-Befehle sind als Skript-Engines gedacht, die den Inhalt Ihres Skripts ausführen. es könnte bash
sein , perl
, oder was auch immer, aber die Erwartung ist, dass es mit dem Dateinamen eines auszuführenden Skripts aufgerufen wird. Wie funktioniert bash
Tu es? Es rät nicht. Wenn es auf ein Argument stößt, das nicht wie eine Option aussieht (oder das Argument einer Option), behandelt es es als das auszuführende Skript; Argumente danach werden an das Skript übergeben. Zum Beispiel:
/bin/bash -x -e somename foo bar
Hier sucht bash nach der Datei somename
und versuchen Sie, es als Skript mit den Argumenten foo
auszuführen und bar
. Sie sollten dasselbe tun, weil Sie vielleicht <mypgm> <myscript>
schreiben möchten eines Tages auf der Kommandozeile.
Wenn Sie die Verwendung von <mypgm>
ohne Skript wünschen um die Voreinstellung zu sein, können Sie verlangen, dass ein Skript mit <mypgm> -f <myscript>
übergeben wird . So funktioniert sed
macht es. Dann würden Sie es in einer Shebang-Zeile wie dieser verwenden:
#!<mypgm> -f
Wenn Sie möchten, dass die Groß-/Kleinschreibung die Vorgabe ist, wie bei bash
und perl
, erstellen Sie eine Option, die besagt, dass diesmal kein Skript vorhanden ist. Sie könnten --
verwenden dafür, damit <mypgm> -- one two three
versucht nicht, one
auszuführen (oder etwas anderes) als Skript. In diesem Fall würde die Shebang-Zeile einfach lauten:
#!<mypgm>
Jetzt muss ich wissen, wann blabla mit dem Shebang aufgerufen wird oder nicht:
In C erhalten Sie diese Informationen über getauxval(AT_EXECFN)
, die Ihnen den Namen der ursprünglichen ausführbaren Datei mitteilt (dh das erste Argument, das an execve(2)
übergeben wird ) [1].
Aber diese Zeichenfolge wird unmittelbar nach den Befehlszeilenargumenten und Umgebungszeichenfolgen am Ende von [stack]
in den Speicher gestellt Speicherregion, sodass es direkt von dort geholt werden kann.
Zum Beispiel das folgende Perl-Skript (nennen Sie es foo.pl
), falls mit chmod 755 foo.pl
ausführbar gemacht , gibt ./foo.pl
aus bei direkter Ausführung und /usr/bin/perl
wenn es als perl ./foo.pl
ausgeführt wird :
#! /usr/bin/perl
open my $maps, "/proc/self/maps" or die "open /proc/self/maps: $!";
my $se;
while(<$maps>){ $se = hex($1), last if /^\w+-(\w+).*\[stack\]$/ }
open my $mem, "/proc/self/mem" or die "open /proc/self/mem: $!";
sysseek $mem, $se - 512, 0;
sysread $mem, $d, 512 or die "sysread: $!";
print $d =~ /([^\0]+)\0+$/, "\n";
Auf neueren (>=3.5) Linux-Kernels ist das Ende der Umgebung auch in /proc/PID/stat
verfügbar (im 51. Feld, wie im proc(5)
dokumentiert Handbuch).
#! /usr/bin/perl
open my $sh, "/proc/self/stat" or die "open /proc/self/stat: $!";
my @s = <$sh> =~ /\(.*\)|\S+/g;
open my $mem, "/proc/self/mem" or die "open /proc/self/mem: $!";
seek $mem, $s[50], 0;
$/ = "\0";
my $pn = <$mem> or die "readline: $!"; chomp $pn; print "$pn\n";
[1] Linux-Kernel neuer als 2.6.26 führten den darauf verweisenden aux-Vektoreintrag ein (siehe Commit), aber der Name der ausführbaren Datei war lange vorher am Ende des Stacks verfügbar (seit Linux-2.0 von 1996).