C与Shell的如何互传信息
一、引子
在很多时候,我们期望C程序与Shell能够互传信息。比如:我们需要用Shell来控制C程序的执行,并且希望C程序能从Shell中获取相关信息;同样,我们也需要从C程序中返回一些信息给Shell,以便Shell根据返回信息执行下一步操作。
二、Shell传递信息给C程序
熟悉Linux下C编程的人都知道,C语言中"main"函数有与Shell命令的接口:
int main(int argc, char **argv)
{
// body of main
}
其中,"argc"(argument counts)表示传入参数的个数,"argv"(argumen values)表示传入参数的值。
来看下面一段代码:
#include <stdio.h>
int main(int argc, char **argv)
{
printf(" argc = %d ", argc);
printf(" argv0 = %s ", argv[0]);
printf(" argv1 = %s ", argv[1]);
printf(" argv2 = %s ", argv[2]);
return 0;
}
将其编译链接为可执行文件"./exchange_msg_shell",并且在shell命令行执行:
./exchange_msg_shell hello world
其输出如下:
argc = 3
argv0 = ./exchange_msg_shell
argv1 = hello
argv2 = world
参数"argc"存储了传入参数的个数,参数"argv"以数组的形式存储了传入参数的值,并且第一个值"argv[0]"表示该可执行文件的文件名,"argv[1], argv[2]"依次表示后面紧跟的参数值。
需要进一步说明的是,参数以字符串的形式进行传递,即使传递是数值类型(整形int,浮点型float等等),因为数组“argv”的类型是"char"。那么,如果我们要从Shell接收数值类型的输入该怎么办呢?我们可以先从Shell接收字符类型的输入,然后在C程序内部,使用类型转换,将字符类型转换为我们所需要的数值类型。C语言中将字符串转换为整数的函数是"atoi"(ascii to integer),将字符串转化为浮点数的函数是"atof"(ascii to floating point numbers),它们均包含在头文件"#include<stdlib.h>"中,接收一个字符串作为输入参数,输出参数为"int"或"float"类型的数。
三、C程序传递信息给Shell
C程序执行总会有个返回值,一般而言,如果顺利执行结束,最后main函数会返回一个值"0";而一旦执行过程中报错,C程序会返回一个非0值。(返回值因程序设计编写的不同而不同,一般而言返回值为0代表顺利执行结束;而返回值为非0值表示执行过程中出错)
其实,用Shell命令运行C程序时,该C程序和普通的Shell命令如出一辙。执行Shell命令时,执行成功,会返回一个值0;执行失败,会返回一个非0值。并且,Shell中有一个系统环境变量"$?"来保存上次执行命令的返回值的。这样,我们就可以在执行完C程序后,通过系统环境变量"$?"来判断C程序是否顺利执行了。比如,在当前目录下有一个文件夹“./test1”,我们可以使用命令"cd"切换到文件夹"./test1":
cd test1/
这个操作是成功的,命令行没有返回任何信息(按照UNIX的哲学:“没有消息就是好消息”),但其实系统用变量"$?"来记录了该命令的返回值(也称为命令的退出状态),我们可以显示出"$?"的值:
echo $?
其输出为"0",说明该命令执行成功。我们再试图用命令"cd"切换到一个当前文件夹中不存在的文件夹"./test2":
cd test2/
终端会打印一条错误信息:
bash : cd : test2/: No such file or directory
来告诉我们当前文件夹下不存在"test2/"文件夹。这时我们再来看变量"$?"值,发现是一个非零值。
我们自己通过源代码编译链接所形成的可执行文件,和普通的Shell命令没本质的区别,Shell也会通过变量"$?"来记录执行其返回值。但这种通过系统环境变量"$?"来传递信息的方式,传递的信息量太少了,只能知道C程序执行成功与否。如果我们期望在Shell中获得更多关于C程序的信息,就必须得在C程序中有相应的输出存储到相关文件中(比如:C程序执行的日志文件),然后用Shell从该文件中读取信息,进行下一步处理。