[LINUX] Scripting Language C —— Comment un fichier texte sans shebang est exécuté

Est-il possible de créer un fichier source en langage C qui peut être exécuté tel quel?

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.

Proposition 1: Utiliser TCC avec shebang

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.

Proposition 2: ajoutez simplement l'attribut d'exécution

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

Lorsqu'il est exécuté depuis le shell

$ 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`.

Comportement du shell 1: Exécuter . / Hello_x.c → Échec

Premiè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`.

Comportement du shell 2: exécuter le shell lui-même

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.

Lorsqu'il est exécuté à partir d'un programme autre que le shell

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.

Proposition 3: fichier source à la fois langage C et script shell

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

Licence pour cet article

[Licence Creative Commons](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

Scripting Language C —— Comment un fichier texte sans shebang est exécuté
Utilisez un langage de script pour une vie confortable en C ++
Créer un fichier qui peut être exécuté dans le langage de script
Comment afficher la date de modification d'un fichier en langage C jusqu'à nanosecondes
Comment implémenter provisoirement une barre de progression dans un langage de script
Utilisez un langage de script pour une vie C ++ confortable-OpenCV-Port Python vers C ++ -
Exporter un fichier texte compressé gzip
[Langage C] Comment créer, éviter et créer un processus zombie
J'ai fait beaucoup de recherches sur la façon dont Python est exécuté
Comment créer un fichier de configuration
Utilisons un langage de script pour une vie C ++ confortable 2 Générer automatiquement une source C ++
Utilisons le langage de script pour une vie confortable en C ++ 4 - Utilisons la propre bibliothèque de C ++ à partir du langage de script -
Utilisez un langage de script pour une vie confortable en C ++ 3-Laissez le graphique à matplotlib-
Qu'est-ce qu'une bibliothèque en langage C? Quelles informations sont ouvertes au public?
[Langage C] Ma locomotive est trop lente ~ J'ai fait une commande sl ~