There are many definitions of what a scripting language is, but the convenience of being able to "run" the source file is important. For example, suppose you have a C source file like the one below.
$ file hello.c
hello.c: C source, ASCII text
$ gcc -Wall ./hello.c
$ ./a.out
Hello, script language C.
Correct code for C that compiles properly without warning. Assuming that this source file is executed with the execution attribute given
$ #Make the source file an executable file like a scripting language
$ chmod +x hello.c
$ ./hello.c
Hello, script language C.
If it is executed without any problem like, C language may be said to be a scripting language. Consider whether you can create such a file.
In a scripting language, the first line of a source file specifies the command to execute that source file, such as #! / Bin / sh
, #! / Usr / bin / python
.
It is "shebang".
Let's use this in C as well.
The compiler called TCC has an option called -run
, which automatically compiles and runs, but you can also specify this on the shebang line.
hello_tcc.c
#!/usr/bin/tcc -run
#include <stdio.h>
int main (int argc, char* argv[]) {
printf("Hello, script language C.\n");
return 0;
}
Now you can run the tcc
command directly in your environment.
$ chmod +x hello_tcc.c
$ ./hello_tcc.c
Hello, script language C.
But is this correct for C?
$ gcc -Wall ./hello_tcc.c
./hello_tcc.c:1:2: error: invalid preprocessing directive #!
#!/usr/bin/tcc -run
^
After all, the shebang line will result in an error. It can only be compiled with TCC.
If there is a shebang line, it will not be in C language, so delete it.
hello_x.c(Add execution attribute)
#include <stdio.h>
int main (int argc, char* argv[]) {
printf("Hello, script language C.\n");
return 0;
}
It's just a text file anymore, but it's not that it's prepaid.
$ chmod +x hello_x.c
$ ./hello_x.c
./hello_x.c: 2: ./hello_x.c: Syntax error: "(" unexpected
You're getting a syntax error. Check the behavior of the shell to see what is giving this error.
$ #(Because my environment is Linux`strace`By command)
$ strace -f sh -c './hello_x.c'
Excerpt from strace output
[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
I extracted two lines of related parts.
[ʻExecve](https://linuxjm.osdn.jp/html/LDP_man-pages/man2/execve.2.html) provides the most basic functions of the Unix exec functions. In Linux etc. this is a system call as it is, so it appears in
strace`.
./hello_x.c
→ FailureFirst, I run ./hello_x.c
on ʻexecve` and get an error.
- ENOEXEC:
The executable could not be executed due to an incomprehensible format, a different architecture, or some other format error.
Text files without shebang cannot be executed in ʻexecve`.
Immediately after failing to execute ./hello_x.c
, it is executing itself (sh
) with ./hello_x.c
as an argument (how to achieve this behavior is slightly different depending on the shell). You may not use ʻexecve` in some situations).
This is the behavior specified in the shell specifications.
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
Translation: If the ʻexecve () `function fails with an error equivalent to the [ENOEXEC] error, the shell executes the same command that calls the shell with the command name as the first operand, with the remaining arguments. It will be passed to the new shell.
However, since ./hello_x.c
is not a shell script, it causes a syntax error, which means that the above error is displayed.
I found that when I run a file without a shebang from a shell, it is run as a shell script by the shell itself. But what if it was run from another program?
$ chmod +x ./hello_x.c
$ env ./hello_x.c
./hello_x.c: 2: ./hello_x.c: Syntax error: "(" unexpected
The above is an example of the ʻenv` command, but with the same results as running it in a shell. This is because some of the exec functions do the same thing as the shell.
If the header of the file is not recognized as executable (the execve (2) you try to call then fails with the error ENOEXEC), these functions shell the file as the first argument (/ bin / sh )
Programs that look for commands in the environment variable PATH
, such as the shell, often use these functions or throw them into the shell from the beginning.
Therefore,
** "Files with execution attributes but no shebang are not certain, but are usually passed to the shell and executed as a shell script" **
It looks good to say.
In the previous plan, it turned out that C language was executed as a shell script as it was and an error occurred. All you have to do is think of a code that meets the following conditions.
C language preprocessor directives begin with #
.
We take advantage of this being a comment in shell scripts.
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;
}
When executed as a shell script, ʻexecwill execute TCC, so the subsequent C language code will not be executed. When it is interpreted as C language,
SHELL_SCRIPT_CODE is ʻundef
, so the shell script part is always skipped.
Can be run as a script
$ chmod +x hello_c_and_sh.c
$ ./hello_c_and_sh.c
Hello, script language C.
It is also a C language source file that can be compiled normally.
$ gcc -Wall ./hello_c_and_sh.c
$ ./a.out
Hello, script language C.
I used TCC because it can be written short, but I also tried to support a compiler that seems to be a little more common.
#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;
}
If there is no TCC, compile, execute, delete the executable file, etc. with c99
.
If you want to make sure to delete the executable file created in / tmp /
, you may need to devise a little more, but for the time being, it will be completed.
[](http://creativecommons.org/licenses/by-sa/4.0/ deed.ja) This article is published under CC BY-SA 4.0 (Creative Commons Attribution 4.0 Inheritance International License).
Recommended Posts