Es gibt viele Definitionen für eine Skriptsprache, aber die Bequemlichkeit, die Quelldatei "ausführen" zu können, ist wichtig. Angenommen, Sie haben eine Quelldatei in C-Sprache wie die folgende.
$ file hello.c
hello.c: C source, ASCII text
$ gcc -Wall ./hello.c
$ ./a.out
Hello, script language C.
Richtiger Code für die C-Sprache, der ohne Vorwarnung ordnungsgemäß kompiliert wird. Angenommen, diese Quelldatei wird mit dem angegebenen Ausführungsattribut ausgeführt
$ #Machen Sie die Quelldatei zu einer ausführbaren Datei wie einer Skriptsprache
$ chmod +x hello.c
$ ./hello.c
Hello, script language C.
Wenn es ohne Probleme wie ausgeführt wird, kann C-Sprache als Skriptsprache bezeichnet werden. Überlegen Sie, ob Sie eine solche Datei erstellen können.
In der Skriptsprache gibt die erste Zeile einer Quelldatei den Befehl zum Ausführen dieser Quelldatei an, z. B. "#! / Bin / sh", "#! / Usr / bin / python". Es ist "shebang. Verwenden wir dies auch in C-Sprache.
Der TCC-Compiler verfügt über eine Option namens "-run", die automatisch kompiliert und ausgeführt wird. Sie können diese jedoch auch in der Shebang-Zeile angeben.
hello_tcc.c
#!/usr/bin/tcc -run
#include <stdio.h>
int main (int argc, char* argv[]) {
printf("Hello, script language C.\n");
return 0;
}
Jetzt können Sie den Befehl tcc
direkt in Ihrer Umgebung ausführen.
$ chmod +x hello_tcc.c
$ ./hello_tcc.c
Hello, script language C.
Aber ist das richtig für die C-Sprache?
$ gcc -Wall ./hello_tcc.c
./hello_tcc.c:1:2: error: invalid preprocessing directive #!
#!/usr/bin/tcc -run
^
Immerhin führt die Shebang-Linie zu einem Fehler. Es kann nur mit TCC kompiliert werden.
Wenn es eine Shebang-Zeile gibt, wird diese nicht in C-Sprache angezeigt. Löschen Sie sie daher.
hello_x.c(Ausführungsattribute hinzufügen)
#include <stdio.h>
int main (int argc, char* argv[]) {
printf("Hello, script language C.\n");
return 0;
}
Es ist nur noch eine Textdatei, aber es ist nicht so, dass sie im Voraus bezahlt wird.
$ chmod +x hello_x.c
$ ./hello_x.c
./hello_x.c: 2: ./hello_x.c: Syntax error: "(" unexpected
Sie erhalten einen Syntaxfehler. Überprüfen Sie das Verhalten der Shell, um festzustellen, was diesen Fehler verursacht.
$ #(Weil die vorliegende Umgebung Linux ist`strace`Auf Befehl)
$ strace -f sh -c './hello_x.c'
Auszug aus der Strace-Ausgabe
[pid 20349] execve("./hello_x.c", ["./hello_x.c"], [/* 80 vars */]) = -1 ENOEXEC (Exec format error)
[pid 20349] execve("/bin/sh", ["/bin/sh", "./hello_x.c"], [/* 80 vars */]) = 0
Ich habe zwei Zeilen verwandter Teile extrahiert.
execve
bietet die grundlegendsten Funktionen der Unix exec-Funktionen.
Unter Linux usw. ist dies ein Systemaufruf wie er ist, daher erscheint er in "strace".
. / Hello_x.c
aus → FehlerZuerst starte ich . / Hello_x.c
mit execve
und erhalte eine Fehlermeldung.
- ENOEXEC:
Die ausführbare Datei konnte aufgrund eines unverständlichen Formats, einer anderen Architektur oder eines anderen Formatfehlers nicht ausgeführt werden.
Textdateien ohne Shebang können nicht auf "Ausführen" ausgeführt werden.
Unmittelbar nachdem ich . / Hello_x.c
nicht ausgeführt habe, führe ich mich selbst ( sh
) mit . / Hello_x.c
als Argument aus (wie dieses Verhalten erreicht werden kann, hängt von der Shell ab). In einigen Situationen verwenden Sie möglicherweise nicht execve
).
Dies ist das in den Shell-Spezifikationen angegebene Verhalten.
If the execve() function fails due to an error equivalent to the [ENOEXEC] error, the shell shall execute a command equivalent to having a shell invoked with the command name as its first operand, with any remaining arguments passed to the new shell —— Shell Command Language
Übersetzung: Wenn die Funktion
execve ()
aufgrund eines Fehlers fehlschlägt, der dem Fehler [ENOEXEC] entspricht, führt die Shell denselben Befehl aus, der die Shell mit dem Befehlsnamen als erstem Operanden aufruft, und die verbleibenden Argumente sind Es wird an die neue Shell übergeben.
Da . / Hello_x.c
jedoch kein Shell-Skript ist, verursacht es einen Syntaxfehler, was bedeutet, dass der obige Fehler angezeigt wird.
Es stellt sich heraus, dass eine Datei, die ohne Shebang in der Shell ausgeführt wird, von der Shell selbst als Shell-Skript ausgeführt wird. Aber was ist, wenn es von einem anderen Programm ausgeführt wurde?
$ chmod +x ./hello_x.c
$ env ./hello_x.c
./hello_x.c: 2: ./hello_x.c: Syntax error: "(" unexpected
Das Obige ist ein Beispiel für den Befehl "env", jedoch mit dem gleichen Ergebnis wie das Ausführen in einer Shell. Dies liegt daran, dass einige der exec-Funktionen dasselbe wie die Shell tun.
Wenn der Header der Datei nicht als ausführbar erkannt wird (die Execve (2), die Sie aufrufen möchten, schlägt mit dem Fehler ENOEXEC fehl), werden diese Funktionen die Datei als erstes Argument (/ bin / sh) schälen. )
Programme wie die Shell, die nach Befehlen in der Umgebungsvariablen "PATH" suchen, verwenden diese Funktionen häufig oder werfen sie von Anfang an in die Shell. Deshalb, ** "Dateien mit Ausführungsattributen, aber ohne Shebang sind nicht sicher, werden aber normalerweise an die Shell übergeben und als Shell-Skript ausgeführt." ** Es sieht gut aus zu sagen.
Im vorherigen Plan stellte sich heraus, dass die C-Sprache so wie sie war als Shell-Skript ausgeführt wurde und ein Fehler auftrat. Sie müssen sich nur einen Code vorstellen, der die folgenden Bedingungen erfüllt.
C-Sprach-Präprozessor-Direktiven beginnen mit "#". Wir nutzen dies als Kommentar in Shell-Skripten.
hello_c_and_sh.c
#undef SHELL_SCRIPT_CODE
#ifdef SHELL_SCRIPT_CODE
exec tcc -run "$0" "$@"
#endif
#include <stdio.h>
int main (int argc, char* argv[]) {
printf("Hello, script language C.\n");
return 0;
}
Bei Ausführung als Shell-Skript wechselt exec
zur TCC-Ausführung, sodass nachfolgender C-Sprachcode nicht ausgeführt wird.
Bei der Interpretation als C-Sprache ist SHELL_SCRIPT_CODE undef, sodass der Shell-Skriptteil immer übersprungen wird.
Kann als Skript ausgeführt werden
$ chmod +x hello_c_and_sh.c
$ ./hello_c_and_sh.c
Hello, script language C.
Es ist auch eine Quelldatei in C-Sprache, die normal kompiliert werden kann.
$ gcc -Wall ./hello_c_and_sh.c
$ ./a.out
Hello, script language C.
Ich habe TCC verwendet, weil es kurz geschrieben werden kann, aber ich habe auch versucht, einen Compiler zu unterstützen, der etwas häufiger vorkommt.
#undef SHELL_SCRIPT_CODE
#ifdef SHELL_SCRIPT_CODE
command -v tcc >/dev/null 2>/dev/null && exec tcc -run "$0" "$@"
tmp_execute="$(mktemp /tmp/tmp_execute.XXXXXX)"
c99 -o "$tmp_execute" "$0"
"$tmp_execute" "$@"
exit_code="$?"
rm "$tmp_execute"
exit "$exit_code"
#endif
#include <stdio.h>
int main (int argc, char* argv[]) {
printf("Hello, script language C.\n");
return 0;
}
Wenn es keine TCC gibt, kompilieren, ausführen, löschen Sie die ausführbare Datei usw. mit c99
.
Wenn Sie sicherstellen möchten, dass die in / tmp /
erstellte ausführbare Datei gelöscht wird, müssen Sie möglicherweise etwas mehr entwickeln, diese wird jedoch vorerst abgeschlossen sein.
[](http://creativecommons.org/licenses/by-sa/4.0/ deed.ja) Dieser Artikel wurde unter CC BY-SA 4.0 (Creative Commons Attribution 4.0 Inheritance International License) veröffentlicht.
Recommended Posts