Linux进程-命令行参数和环境列表
命令行参数
在C中,main函数有很多的变种,比如
main(), int main(), int main(int argc, char *argv[]), int main(int argc, char *argv[], char *env[])。
在很长一段时间里(特别是在windows下),我都不清楚后面两种main函数中这么多参数有什么用,直到转到linux下,才明白了这些参数并不是多余的。
int main(int argc, char *argv[])。这两个参数也就是我们在命令行中跟在要执行程序名后面的参数。比如 ./necho hello world。参数的个数存储在argc中(在这个例子中是3,necho也算参数),参数的内容存储在argv指向的一个二维数组中(necho存储在二维数组中的第一个位置),参数名后面都以NULL结尾。
使用argv[0]的一点小技巧
在实际工作中,我们可以对一个程序创建多个不同名称的链接。当从不同名称的链接执行该程序时,我们在程序中可以通过argv[0]知道到底是哪个链接在执行该程序,这样我们就可以调用程序的不同部分来执行。这样做的好处是,同一个程序在不同链接名的调用下,表现出不同程序的特性。
几种不使用main函数参数来获得命令行参数的用法(不可移植):
1.在linux系统中,可以通过/proc/PID/cmdline来获得命令行参数,但是参数之间的空格被忽略。比如上面例子中,如果cat /proc/PID/cmdline 将会得到./nechohelloworld。如果在程序中可以通过下面代码来获得命令名:
int fd = open(“/proc/self/cmdline”, O_RDONLY);
read(fd, buff, 100);
2.在C库中,为了使程序能知道命令的路径,提供了两个全局变量program_invocation_name, program_invocation_short_name(定义在<errno.h>,必须在程序中定义_GNU_SOURCE)。第一个全局变量提供了命令的完整路径,而第二个只提供了一个命令名。比如/home/share/src/necho和necho。
通常情况下,我们的命令行参数不会多到溢出,不过了解存储该参数的空间大小对编程也没什么坏处。我们可以通过ARG_MAX(定义在<limits.h>)这个宏或者sysconf(_SC_ARG_MAX)系统调用来了解参数空间大小(该空间存储命令行参数和环境变量)。在linux系统上,ARG_MAX曾经被固定的设置为32个页的大小。但是从2.6.32起,该存储空间的大小被定义为RLIMIT_STACK的四分之一。
环境变量
每个进程都有相关联的环境列表(Environment List),环境列表由多个环境字符串组成。环境字符串被定义成name=value格式。name叫做环境变量(Environment Variable)。
当一个进程被创建时,该进程继承父进程的环境列表。这个特性可以作为父进程和子进程通信的一种方法。比如,当父进程要创建子进程时,可以先设置某个环境变量,子进程随后在自己的环境列表中读取该环境变量。不过这种通信是单向的(one-way)和一次性的(once-only),子进程在创建后,就完全拥有和父进程独立环境列表了。程序可以通过检查环境变量来改变程序的特性(像使用命令行参数一样)。
环境变量通常在shell中使用,在shell中创建的进程都继承了shell的环境列表。通常在bash下,我们像下面这样使用环境变量:
export SHELL = /bin/bash
如果只是想设置某一个程序的环境变量,可以这样使用:
name1=var1 name2=var2 nameN=varN program
使用printenv显示当前的环境列表:
$printenv
SHELL=/bin/bash
HOME=/home/ddb
PATH=/usr/local/bin:/usr/bin:/bin:
可以通过cat /proc/PID/environ来查看进程环境列表。
程序中如何使用环境列表
1.通过全局变量char **environ。environ和argv很相似。也可以通过
int main(int argc, char *argv[], char *envp[])中的envp来访问。
2.使用程序提供的API。
char *getenv(const char *name)
注意点:
a.该函数返回指定环境变量的字符值。
b.不要直接修改返回值,因为在类UNIX的大部分实现中,返回指针实际上是指向环境字符串中的value部分的。如果要改变该值,使用setenv()或putenv()。
c.当程序得到一个返回指针后,要用一个私有buff来保存该值。因为在某些实现中,该函数内部使用一个静态buff来保存需要返回的值,这使得在下一次函数被调用后,静态buff中的值被其他值覆盖。
int putenv(char *string)
注意点:
1.成功返回-0,失败返回-非0(不是-1)。
2.string的格式为”name=value”。
3.不要把string声明成自动变量,string将成为环境列表的一部分,也就是说,该程序不会复制string到环境列表中,而是把string当做列表的一部分,当程序中改变string,会影响该进程的环境变量。
4.使用该函数通常是父进程想让它所创建的子进程继承某个改变的环境变量。或者是想让自己根据改变的环境变量来改变程序的特性(先改变某些环境变量,然后执行exec()函数群来调用自己,程序重启,然后根据这些改变的环境变量来改变程序运行的特性)。
int setenv(const char *name, const char *value, int overwrite)
int unsetenv(const char *name)
注意点:
1.setenv()会创建一个新的buff来存储参数“name=value“(跟putenv对比),我们没必要再name后面或value前面添加”=”号,因为在该函数中会自动添加。
2.只有在overwrite为非0,环境变量才会改变。
#define _BSD_SOURCE
int clearenv(void)
注意点:
1.该函数清除整个环境列表。也可以通过environ=NULL来清除。
2.当该函数跟setenv()一起使用时,会产生内存泄露。因为clearenv()不会清除setenv()分配的内存。这两个函数不会频繁的调用,所有通常不是什么大问题。
ABI的讨论
Application Binary Interface是一组规则,它指定了一个二进制程序在运行时如何和内核、库交换信息。ABI指定了交换信息的寄存器和栈位置。一个ABI兼容的程序被编译后,它就可以在所有ABI兼容的系统上运行了。
Linux进程-命令行参数和环境列表的更多相关文章
- Linux学习心得之 Linux下命令行Android开发环境的搭建
作者:枫雪庭 出处:http://www.cnblogs.com/FengXueTing-px/ 欢迎转载 Linux学习心得之 Linux下命令行Android开发环境的搭建 1. 前言2. Jav ...
- 关于Arch Linux efibootmgr 命令行参数问题
相关链接: https://wiki.archlinux.org/index.php/EFISTUB 今天安装Arch Linux 在 efibootmgr创建启动项时,总是提示 UUID=xxxx ...
- .NET Core采用的全新配置系统[5]: 聊聊默认支持的各种配置源[内存变量,环境变量和命令行参数]
较之传统通过App.config和Web.config这两个XML文件承载的配置系统,.NET Core采用的这个全新的配置模型的最大一个优势就是针对多种不同配置源的支持.我们可以将内存变量.命令行参 ...
- 命令行参数(argc, argv)
每个C语言程序都必须有一个称为main()的函数,作为程序启动的起点.当执行程序时,命令行参数(command-line argument)(由shell逐一解析)通过两个入参提供给main()函数. ...
- Linux 进程(一):环境及其控制
进程环境 main启动 当内核执行C程序时,在调用main前先调用一个特殊的启动例程.可执行程序将此启动例程指定为程序的起始地址,接着启动例程从内核中取出命令行参数和环境变量值,然后执行main函数. ...
- Python_sys.argv 命令行参数获取使用方法
import sys print(sys.argv) """ 获取命令行参数 输入 python3 sys.argv_demo.py 输出: ['argv.py'] 输入 ...
- python 处理命令行参数--转载
标题写了那么久,现在现在才有时间,整理下自己的思路.首先先总结下自己对sys模块的理解.手册上对sys的描述是系统参数和系统函数,这里的系统实际上是python解释器.这个模块提供了用户可以访问的解释 ...
- linux bash Shell特殊变量:Shell $0, $#, $*, $@, $?, $$和命令行参数
在linux下配置shell参数说明 前面已经讲到,变量名只能包含数字.字母和下划线,因为某些包含其他字符的变量有特殊含义,这样的变量被称为特殊变量. 例如,$ 表示当前Shell进程的ID,即pid ...
- LibOpenCM3(一) Linux下命令行开发环境配置
目录 LibOpenCM3(一) Linux下命令行开发环境配置 本文使用 Linux 环境, 硬件为 STM32F103 系列开发板 LibOpenCM3 介绍 LibOpenCM3 是GPL协议( ...
随机推荐
- java连接sqlserver2008
java连接sqlserver2008时应有sqljdbc4.jar驱动包.连接的示例代码如下: import java.sql.*; public class ConnectSQL { public ...
- Python练习之pillow
此系列意在记录于一些有趣的程序及对其的总结. 问题来源: https://github.com/Yixiaohan/show-me-the-code https://github.com/HT524/ ...
- CSS布局套路
这篇笔记的目的是记录分别应用float和flex布局的方法.主要是对遇到的问题进行总结. 1.float布局 总结: 1.1 使用float布局要清除浮动,清除的方法是,在父元素添加如下样式 .cle ...
- Docker 镜像
Docker 镜像就是一个只读的模板. 例如:一个镜像可以包含一个完整的 ubuntu 操作系统环境,里面仅安装了 Apache 或用户需要的其它应用程序. 镜像可以用来创建 Docker 容器. D ...
- NLP系列(2)_用朴素贝叶斯进行文本分类(上)
作者:龙心尘 && 寒小阳 时间:2016年1月. 出处: http://blog.csdn.net/longxinchen_ml/article/details/50597149 h ...
- Swift基础之两指拉动图片变大变小
我们在使用APP的时候,有时会发现有些图片可以通过两指进行放大.缩小,今天就实现这样的一种效果,比较简单,不喜勿喷.... var imageVi:UIImageView! = nil var ...
- Tomcat如何实现Comet
Comet模式是一种服务器端推技术,它的核心思想提供一种能让当服务器端往客户端发送数据的方式.Comet模式为什么会出现?刚开始人们在客户端通过不断自动刷新整个页面来更新数据,后来觉得体验不好又使用了 ...
- springMVC源码分析--SimpleServletHandlerAdapter(二)
上一篇博客springMVC源码分析--HandlerAdapter(一)中我们主要介绍了一下HandlerAdapter接口相关的内容,实现类及其在DispatcherServlet中执行的顺序,接 ...
- 关于在页面中针对不同版本的IE浏览器实现不同的JS或者CSS样式
一般会用到<!--[if IE]>这里是正常的html代码<![endif]--> 条件注释只能在windows Internet Explorer(以下简称IE)下使用,因此 ...
- Linux 环境下的一些常用命令(三)
转载自 http://www.oschina.net/translate/20-advanced-commands-for-middle-level-linux-users 21. 命令: Find ...