GNU/Linux >> LINUX-Kenntnisse >  >> Linux

Shebang oder nicht Shebang

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).


Linux
  1. Kann ein Bash-Skript mit einer Datei verknüpft werden?

  2. Shell-Skript:Bedingung „wenn Datei nicht verwendet wird“?

  3. nano:Befehl nicht gefunden

  4. Sortieren:Befehl nicht gefunden

  5. sed:Befehl nicht gefunden

35 Bash-Skriptbeispiele

tail:Befehl nicht gefunden

touch:Befehl nicht gefunden

nohup:Befehl nicht gefunden

atomare Erstellungsdatei, falls nicht aus dem Bash-Skript vorhanden

Das SH-Skript in $PATH wird unter Linux Alpine 3.11 nicht gefunden