文章目录
使用C程序访问环境变量
系统提供了一个全局变量
extern char **environ;
使用全局变量environ将所有的环境变量输出。
相关API函数
getenv(3)
#include <stdlib.h>
char *getenv(const char *name);
功能:获取环境变量的值
参数:
name:环境变量的名字
返回值:
NULL 没有找到这个环境变量
返回环境变量的值的首地址。
putenv(3)
#include <stdlib.h>
int putenv(char *string);
功能:改变一个环境变量的值,或者增加一个环境变量
参数:
string:name=value
返回值:
0 成功
非0 错误
clearenv(3)
#include <stdlib.h>
int clearenv(void);
功能:清除环境变量
参数:
void
返回值:
0 成功
非0 失败
setenv(3)
#include <stdlib.h>
int setenv(const char *name,const char *value,int overwrite);
功能:改变或增加一个环境变量
参数:
name:指定了环境变量的名字
value:指定了环境变量的值
overwrite:
0 环境变量存在,那么值不改变。
非0 环境变量存在,值被替换。
返回值:
0 成功
-1 失败 errno被设置
int unsetenv(const char *name);
功能:删除环境变量
参数:
name:指定环境变量的名字
返回值:
0 成功
-1 失败 errno被设置
代码示例
- myenv.c
#include <stdio.h>
int main(void){
extern char **environ;
int i=0;
while(*(environ+i)!=NULL){
printf("%s\n",*(environ+i));
i++;
}
return 0;
}
-
执行结果
-
myenv1.c
#include <stdio.h>
int main(int argc,char *argv[],char *envp[]){
int i=0;
for(;envp[i]!=NULL;i++){
printf("%s\n",envp[i]);
}
return 0;
}
-
执行结果
-
env_test.c
#include <stdio.h>
#include <stdlib.h>
int main(void){
printf("USER:%s\n",getenv("USER"));
putenv("name=tarena");
printf("name:%s\n",getenv("name"));
// putenv("name=pycoming");
setenv("name","pycoming",1);
printf("name:%s\n",getenv("name"));
unsetenv("name");
printf("name:%s\n",getenv("name"));
clearenv();
printf("USER:%s\n",getenv("USER"));
return 0;
}
- 执行结果
文件输入重定向
代码示例
- upper.c
#include <stdio.h>
#include <ctype.h>
int main(void){
int ch;
while((ch=getchar())!=EOF)
putchar(toupper(ch));
return 0;
}
- 执行结果
- wrap.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
int main(int argc,char *argv[]){
int fd;
fd=open(argv[1],O_RDONLY);
if(fd==-1){
perror("open");
return 1;
}
dup2(fd,STDIN_FILENO);
close(fd);
execl("./upper","upper",NULL);
return 0;
}
- 执行结果
管道
管道分为两种:有名管道、无名管道。
无名管道
无名管道的创建使用pipe
#include <unistd.h>
int pipe(int pipefd[2]);
功能:创建管道
参数:
pipefd[2]:管道的两个文件描述符。
pipefd[0] 读端
pipefd[1] 写端
返回值:
0 成功
-1 错误 errno被设置
代码示例
- pipe.c
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <string.h>
#include <stdlib.h>
int main(void){
pid_t pid;
int fd[2];
char msg[]="this is a test\n";
char buf[128];
//创建管道
int r=pipe(fd);
if(r==-1){
perror("pipe");
return 2;
}
//创建子进程
pid=fork();
if(pid==-1){
perror("fork");
return 1;
}
if(pid==0){//子进程的代码
close(fd[0]);//关闭读端
//向管道写内容
write(fd[1],msg,strlen(msg));
exit(0);
}else{//父进程的代码
close(fd[1]);//管不写端
//从管道读取数据
int rt=read(fd[0],buf,128);
write(1,buf,rt);
//回收子进程的资源
wait(NULL);
}
return 0;
}
- 执行结果
小结
1、父进程创建管道
2、fork(2)创建子进程
3、父进程关闭写端,子进程关闭读端
4、子进程写,父进程读
无名管道中需要使用到文件描述符,所以,无名管道应用于具有亲缘关系的进程间通信。
有名管道
有名管道的实质就是创建一个管道文件,一个进程向文件写数据,另一个进程从文件中读数据。创建有名管道需要使用mkfifo。
mkfifo(3)
#include <sys/types.h>
#include <sys/stat.h>
int mkfifo(const char *pathname, mode_t mode);
功能:创建一个有名的管道文件
参数:
pathname:指定管道文件的名字
mode:指定了管道文件的权限
返回值:
0 成功
-1 错误 errno被设置
代码示例
- channelA.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
int main(int argc,char *argv[]){
char msg[]="hello world\n";
//创建管道文件
int m=mkfifo(argv[1],0664);
if(m==-1){
perror("mkfifo");
return 1;
}
//打开管道文件
int fd=open(argv[1],O_RDWR);
if(fd==-1){
perror("open");
return 2;
}
//向管道文件写入数据
sleep(20);
write(fd,msg,strlen(msg)+1);
//getchar();
close(fd);
return 0;
}
- channelB.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
int main(int argc,char *argv[]){
char buf[128];
//打开管道文件
int fd=open(argv[1],O_RDONLY);
if(fd==-1){
perror("open");
return 1;
}
//从管道中读取数据
int r=read(fd,buf,128);
write(1,buf,r);
close(fd);
return 0;
}
- 执行结果
补充
带有环境变量的加载映像:
- execle.c
#include <stdio.h>
#include <unistd.h>
int main(void){
char *const ps_env[]={"name=tarena"\
,NULL};
execle("./myenv","myenv",NULL,\
ps_env);
return 0;
}
- 执行结果
信号
信号就是软中断,软中断就是软件模拟的中断,中断是系统中的中断服务程序。
信号就是进程的异步通信机制,系统提供的信号可以通过 kill -l查看。
一般来说,信号有64个信号。
kill -信号编号 pid
进程对信号的默认处理动作就是终止当前进程。用户可以根据自己的需求来设置中进程对信号的处理。
SIG_DFL 缺省的
SIG_IGN 忽略
用户自定义信号处理函数
相关API函数
需要想进程注册一个函数,当信号来的时候,使用这个注册的信号处理函数来处理信号的到达。
signal(2)
#include <signal.h>
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);
功能:为信号注册信号处理函数
参数:
signum:信号的名字或者信号编号
handler:
SIG_DFL 默认
SIG_IGN 忽略
用户自定义的信号处理函数
返回值:
SIG_ERR 错误
返回原来的信号处理函数
举例验证,使用signal函数为进程注册信号处理函数。
代码示例
- signal.c
#include <stdio.h>
#include <signal.h>
//用户自定义的信号处理函数
void doit(int n){
printf("recv signal...\n");
return;
}
int main(void){
//进程对2号信号忽略
signal(2,SIG_IGN);
//进程对3号信号处理,采用用户自定义的
signal(3,doit);
while(1);
return 0;
}
- 执行结果
信号的产生
硬件产生信号
ctrl+c
ctrl+\
使用linux命令发送信号
kill -信号编号 pid
使用函数给进程发送信号
kill(2)
#include <sys/types.h>
#include <signal.h>
int kill(pid_t pid, int sig);
功能:发送信号给一个进程
参数:
pid: 正数 进程的pid 给这个进程发送信号
sig: 指定信号编号
返回值:
0 成功
-1 错误 errno被设置
raise(3)
#include <signal.h>
int raise(int sig);
功能:给当前进程发送信号
参数:
sig:要发送的信号编号
返回值:
0 成功
非0 失败
alarm(2)
#include <unistd.h>
unsigned int alarm(unsigned int seconds);
功能:设置一个传递信号的闹钟
参数:
seconds: 设置闹钟的秒数
返回值:
保留的秒数
mykill代码示例
- mykill.c
#include <stdio.h>
#include <sys/types.h>
#include <signal.h>
int main(int argc,char *argv[]){
//mykill 信号编号 pid
int signum=atoi(argv[1]);
pid_t pid=atoi(argv[2]);
//给进程发送2号信号
kill(pid,signum);
return 0;
}
-
执行结果
-
raise.c
#include <stdio.h>
#include <signal.h>
//参数n是信号的编号
void doit(int n){
printf("reav signum ...%d\n",n);
return ;
}
int main(void){
printf("pid:%d\n",getpid());
signal(2,doit);
while(1){
sleep(2);
raise(2);
}
return 0;
}
-
执行结果
-
myalarm.c
#include <stdio.h>
#include <unistd.h>
int main(void){
int i;
alarm(1);
for(i=0;;i++)
printf("%d\n",i);
return 0;
}
- 执行结果