将C或C ++文件作为脚本运行

所以这可能是一个很长的镜头,但有没有办法将C或C ++文件作为脚本运行? 我试过了:

#!/usr/bin/gcc main.c -o main; ./main int main(){ return 0; } 

但它说:

 ./main.c:1:2: error: invalid preprocessing directive #! 

对于C,您可以查看tcc ,即Tiny C编译器。 将C代码作为脚本运行是其可能的用途之一。

 $ cat /usr/local/bin/runc #!/bin/bash sed -n '2,$p' "$@" | gcc -o /tmp/a.out -x c++ - && /tmp/a.out rm -f /tmp/a.out $ cat main.c #!/bin/bash /usr/local/bin/runc #include  int main() { printf("hello world!\n"); return 0; } $ ./main.c hello world! 

sed命令获取.c文件并剥离hash-bang行。 2,$p表示将行2打印到文件末尾; "$@"扩展为runc脚本的命令行参数,即"main.c"

sed的输出通过管道输送到gcc。 传递-到gcc告诉它从stdin读取,当你这样做时,你还必须用-x指定源语言,因为它没有文件名可供猜测。

简短回答:

 //usr/bin/clang "$0" && exec ./a.out "$@" int main(){ return 0; } 

诀窍是你的文本文件必须是有效的C / C ++代码和shell脚本。 请记住在解释器到达C / C ++代码之前exit shell脚本,或者调用exec magic。

使用chmod +x main.c; ./main.c运行chmod +x main.c; ./main.c chmod +x main.c; ./main.c

不需要#!/usr/bin/tcc -run这样的shebang,因为类Unix系统已经在shell中执行了文本文件。

(改编自此评论 )


我在我的C ++脚本中使用它:

 //usr/bin/clang++ -O3 -std=c++11 "$0" && ./a.out; exit #include  int main() { for (auto i: {1, 2, 3}) std::cout << i << std::endl; return 0; } 

如果您的编译行增长太多,您可以使用预处理器(根据此答案改编),因为这个普通的旧C代码显示:

 #if 0 clang "$0" && ./a.out rm -f ./a.out exit #endif int main() { return 0; } 

当然你可以缓存可执行文件:

 #if 0 EXEC=${0%.*} test -x "$EXEC" || clang "$0" -o "$EXEC" exec "$EXEC" #endif int main() { return 0; } 

现在,对于真正古怪的Java开发人员:

 /*/../bin/true CLASS_NAME=$(basename "${0%.*}") CLASS_PATH="$(dirname "$0")" javac "$0" && java -cp "${CLASS_PATH}" ${CLASS_NAME} rm -f "${CLASS_PATH}/${CLASS_NAME}.class" exit */ class Main { public static void main(String[] args) { return; } } 

D程序员只需将一个shebang放在文本文件的开头,而不会破坏语法:

 #!/usr/bin/rdmd void main(){} 

由于shebang行将传递给编译器,而#表示预处理器指令,它将阻塞#!。

你可以做的是将makefile嵌入.c文件中(如本xkcd线程中所述 )

 #if 0 make $@ -f - < extern void bar(); int main(int argc, char* argv[]) { bar(); return EXIT_SUCCESS; } #endif #ifdef BAR_C void bar() { puts("bar!"); } #endif 

围绕makefile的#if 0 #endif对确保预处理器忽略该部分文本,并且EOF标记标记make命令应停止解析输入的位置。

CINT :

CINT是C和C ++代码的解释器。 例如,对于快速开发比执行时间更重要的情况,它很有用。 使用解释器可以大大减少编译和链接周期,从而促进快速开发。 CINT使C / C ++编程即使对于兼职程序员也很有趣。

您可能想要结帐ryanmjacobs / c ,这是为此而设计的。 它充当您喜欢的编译器的包装器。

 #!/usr/bin/c #include  int main(void) { printf("Hello World!\n"); return 0; } 

使用c是你可以选择你想要使用的编译器,例如

 $ export CC=clang $ export CC=gcc 

所以你也得到了所有你最喜欢的优化! 打败那个tcc -run

您也可以向shebang添加编译器标志,只要它们以--字符终止:

 #!/usr/bin/c -Wall -g -lncurses -- #include  int main(void) { initscr(); /* ... */ return 0; } 

如果设置了c也会使用$CFLAGS$CPPFLAGS

John Kugelman的Variatn可以用这种方式写成:

 #!/bin/bash t=`mktemp` sed '1,/^\/\/code/d' "$0" | g++ -o "$t" -x c++ - && "$t" "$@" r=$? rm -f "$t" exit $r //code #include  int main() { printf("Hi\n"); return 0; } 
 #!/usr/bin/env sh tail -n +$(( $LINENO + 1 )) "$0" | cc -xc - && { ./a.out "$@"; e="$?"; rm ./a.out; exit "$e"; } #include  int main(int argc, char const* argv[]) { printf("Hello world!\n"); return 0; } 

这也适当地转发了参数和退出代码。

这是另一种选择:

 #if 0 TMP=$(mktemp -d) cc -o ${TMP}/a.out ${0} && ${TMP}/a.out ${@:1} ; RV=${?} rm -rf ${TMP} exit ${RV} #endif #include  int main(int argc, char *argv[]) { printf("Hello world\n"); return 0; }