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协议( ...
随机推荐
- MySQL EXTRACT() 函数
定义和用法 EXTRACT() 函数用于返回日期/时间的单独部分,比如年.月.日.小时.分钟等等. 语法 EXTRACT(unit FROM date) date 参数是合法的日期表达式.unit 参 ...
- Python3 CGI编程
什么是CGI CGI 目前由NCSA维护,NCSA定义CGI如下: CGI(Common Gateway Interface),通用网关接口,它是一段程序,运行在服务器上如:HTTP服务器,提供同客户 ...
- 百度地图JS 搜索悬浮窗功能
这个需求的效果类似下面的截图,主要还是利用百度地图中自定义控件的功能,挺简单的.文档地址在这 http://lbsyun.baidu.com/index.php?title=jspopular 效果图 ...
- Objective-C与Java类的一些区别
Objective-C与Java类的一些区别 OC类和C一样,需要有声明和定义,先上一段OC代码 #import <Foundation/Foundation.h> /* * 声明一个Pe ...
- 递归dict
一个看起来非常酷的定义 class Example(dict): def __getitem__(self, item): try: return dict.__getitem__(self, ite ...
- 一个貌似比较吊的递归转换为loop--总算成功了.--第二弹
前段时间用类似于散弹式编程的方式,各种猜测-运行验证-修正结果,最终成功转换了一个看起来比较有难度的递归函数.但总觉得很蛋疼,原因如下: 1.虽然正确,但是逻辑搞得比较复杂.现在去看,一头雾水,不知道 ...
- Android捕获全局异常
Android捕获全局异常 程序避免不了出现bug,导致程序崩溃,为了尽量不影响用户体验,可以全局捕获异常 效果图 异常捕获处理前 异常捕获处理后(将程序重新启动) 捕获异常的工具类 package ...
- Linux telnet远程登录操作
telnet (如果不行 可以却换root帐户试试 su - root) 1.安装telnet-server sudo dpkg -i xinetd_1%3a2.3.14-7ubuntu3_ ...
- Afianl加载网络图片(续)
上一篇已经讲了如何利用Afianl加载网络图片和下载文件,这篇文章将继续讲解使用Afinal加载网络图片的使用,主要结合listview的使用: 看效果图: listview在滑动过程中没用明显卡顿, ...
- Android简易实战教程--第二十一话《内容观察者监听数据库变化》
当数据库的数据发生改变,我们又想知道具体改变的情况时,就需要对数据库的变化情况做一个监控.这个任务,就由内容观察者来完成.下面这个案例,为短信数据库注册内容观察者,来监控短信的变化情况,当短信数据库发 ...