Il existe de nombreuses définitions de ce qu'est un langage de script, mais la commodité de pouvoir "exécuter" le fichier source est importante. Par exemple, supposons que vous ayez un fichier source en langage C comme celui ci-dessous.
$ file hello.c
hello.c: C source, ASCII text
$ gcc -Wall ./hello.c
$ ./a.out
Hello, script language C.
Code correct pour le langage C qui se compile correctement sans avertissement. En supposant que ce fichier source est exécuté avec l'attribut d'exécution donné
$ #Faire du fichier source un fichier exécutable comme un langage de script
$ chmod +x hello.c
$ ./hello.c
Hello, script language C.
S'il est exécuté sans problème comme, le langage C peut être considéré comme un langage de script. Demandez-vous si vous pouvez créer un tel fichier.
Dans le langage de script, la première ligne d'un fichier source spécifie la commande pour exécuter ce fichier source, comme #! / Bin / sh
, #! / Usr / bin / python
.
C'est "shebang".
Utilisons également ceci en langage C.
Le compilateur TCC a une option appelée -run
, qui compile et s'exécute automatiquement, mais vous pouvez également le spécifier sur la ligne shebang.
hello_tcc.c
#!/usr/bin/tcc -run
#include <stdio.h>
int main (int argc, char* argv[]) {
printf("Hello, script language C.\n");
return 0;
}
Vous pouvez maintenant exécuter la commande tcc
directement dans votre environnement.
$ chmod +x hello_tcc.c
$ ./hello_tcc.c
Hello, script language C.
Mais est-ce correct pour le langage C?
$ gcc -Wall ./hello_tcc.c
./hello_tcc.c:1:2: error: invalid preprocessing directive #!
#!/usr/bin/tcc -run
^
Après tout, la ligne shebang entraînera une erreur. Il ne peut être compilé qu'avec TCC.
S'il y a une ligne shebang, elle ne sera pas en langage C, alors supprimez-la.
hello_x.c(Ajouter des attributs d'exécution)
#include <stdio.h>
int main (int argc, char* argv[]) {
printf("Hello, script language C.\n");
return 0;
}
Ce n'est plus qu'un fichier texte, mais ce n'est pas qu'il soit prépayé.
$ chmod +x hello_x.c
$ ./hello_x.c
./hello_x.c: 2: ./hello_x.c: Syntax error: "(" unexpected
Vous obtenez une erreur de syntaxe. Vérifiez le comportement du shell pour voir ce qui cause cette erreur.
$ #(Parce que l'environnement actuel est Linux`strace`Par commande)
$ strace -f sh -c './hello_x.c'
Extrait de la sortie strace
[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
J'ai extrait deux lignes de pièces liées.
[ʻExecve](https://linuxjm.osdn.jp/html/LDP_man-pages/man2/execve.2.html) fournit les fonctions les plus basiques des fonctions d'exécution d'Unix. Sous Linux, etc., c'est un appel système tel quel, donc il apparaît dans
strace`.
. / Hello_x.c
→ ÉchecPremièrement, je lance . / Hello_x.c
avec ʻexecve` et j'obtiens une erreur.
- ENOEXEC:
Le fichier exécutable n'a pas pu être exécuté en raison d'un format incompréhensible, d'une architecture différente ou d'une autre erreur de format.
Les fichiers texte sans shebang ne peuvent pas être exécutés sur ʻexecve`.
Immédiatement après avoir échoué à exécuter . / Hello_x.c
, il s'exécute ( sh
) avec . / Hello_x.c
comme argument (comment obtenir ce comportement est légèrement différent selon le shell). Dans certaines situations, vous ne pouvez pas utiliser ʻexecve`).
C'est le comportement spécifié dans les spécifications du shell.
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
Traduction: Si la fonction ʻexecve () `échoue à cause d'une erreur équivalente à l'erreur [ENOEXEC], le shell exécute la même commande qui appelle le shell avec le nom de la commande comme premier opérande, et les arguments restants sont Il sera transmis au nouveau shell.
Cependant, puisque . / Hello_x.c
n'est pas un script shell, il provoque une erreur de syntaxe, ce qui signifie que l'erreur ci-dessus est affichée.
Il s'avère que si vous exécutez un fichier sans shebang depuis le shell, il sera exécuté en tant que script shell par le shell lui-même. Mais que se passerait-il s'il était exécuté à partir d'un autre programme?
$ chmod +x ./hello_x.c
$ env ./hello_x.c
./hello_x.c: 2: ./hello_x.c: Syntax error: "(" unexpected
Ce qui précède est un exemple de la commande ʻenv`, mais avec le même résultat que son exécution dans un shell. Ceci est dû au fait que certaines des fonctions exec font la même chose que le shell.
Si l'en-tête du fichier n'est pas reconnu comme exécutable (l'execve (2) que vous essayez d'appeler échoue alors avec l'erreur ENOEXEC), ces fonctions décortiqueront le fichier comme premier argument (/ bin / sh). )
Des programmes comme le shell qui recherchent des commandes dans la variable d'environnement PATH
utilisent souvent ces fonctions ou les lancent dans le shell depuis le début.
Donc,
** "Les fichiers avec des attributs d'exécution mais pas de shebang ne sont pas certains, mais sont généralement passés au shell et exécutés comme un script shell." **
Cela semble bon à dire.
Dans le plan précédent, il s'est avéré que le langage C était exécuté comme un script shell tel quel et une erreur s'est produite. Il vous suffit de penser à un code qui remplit les conditions suivantes.
Les directives de préprocesseur en langage C commencent par «#». Nous profitons du fait qu'il s'agit d'un commentaire dans les scripts shell.
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;
}
Lorsqu'il est exécuté en tant que script shell, ʻexecpassera à l'exécution TCC, donc le code du langage C suivant ne sera pas exécuté. Lorsqu'il est interprété comme langage C,
SHELL_SCRIPT_CODE est ʻundef
, donc la partie du script shell est toujours ignorée.
Peut être exécuté sous forme de script
$ chmod +x hello_c_and_sh.c
$ ./hello_c_and_sh.c
Hello, script language C.
C'est aussi un fichier source en langage C qui peut être compilé normalement.
$ gcc -Wall ./hello_c_and_sh.c
$ ./a.out
Hello, script language C.
J'ai utilisé TCC car il peut être écrit court, mais j'ai aussi essayé de supporter un compilateur qui semble être un peu plus courant.
#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;
}
S'il n'y a pas de TCC, compilez, exécutez, supprimez le fichier exécutable, etc. avec c99
.
Si vous voulez vous assurer de supprimer le fichier exécutable créé dans / tmp /
, vous devrez peut-être en concevoir un peu plus, mais pour le moment, il sera terminé.
[](http://creativecommons.org/licenses/by-sa/4.0/ deed.ja) Cet article est publié sous CC BY-SA 4.0 (Creative Commons Attribution 4.0 Inheritance International License).
Recommended Posts