命令行参数

在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进程-命令行参数和环境列表的更多相关文章

  1. Linux学习心得之 Linux下命令行Android开发环境的搭建

    作者:枫雪庭 出处:http://www.cnblogs.com/FengXueTing-px/ 欢迎转载 Linux学习心得之 Linux下命令行Android开发环境的搭建 1. 前言2. Jav ...

  2. 关于Arch Linux efibootmgr 命令行参数问题

    相关链接: https://wiki.archlinux.org/index.php/EFISTUB 今天安装Arch Linux 在 efibootmgr创建启动项时,总是提示 UUID=xxxx ...

  3. .NET Core采用的全新配置系统[5]: 聊聊默认支持的各种配置源[内存变量,环境变量和命令行参数]

    较之传统通过App.config和Web.config这两个XML文件承载的配置系统,.NET Core采用的这个全新的配置模型的最大一个优势就是针对多种不同配置源的支持.我们可以将内存变量.命令行参 ...

  4. 命令行参数(argc, argv)

    每个C语言程序都必须有一个称为main()的函数,作为程序启动的起点.当执行程序时,命令行参数(command-line argument)(由shell逐一解析)通过两个入参提供给main()函数. ...

  5. Linux 进程(一):环境及其控制

    进程环境 main启动 当内核执行C程序时,在调用main前先调用一个特殊的启动例程.可执行程序将此启动例程指定为程序的起始地址,接着启动例程从内核中取出命令行参数和环境变量值,然后执行main函数. ...

  6. Python_sys.argv 命令行参数获取使用方法

    import sys print(sys.argv) """ 获取命令行参数 输入 python3 sys.argv_demo.py 输出: ['argv.py'] 输入 ...

  7. python 处理命令行参数--转载

    标题写了那么久,现在现在才有时间,整理下自己的思路.首先先总结下自己对sys模块的理解.手册上对sys的描述是系统参数和系统函数,这里的系统实际上是python解释器.这个模块提供了用户可以访问的解释 ...

  8. linux bash Shell特殊变量:Shell $0, $#, $*, $@, $?, $$和命令行参数

    在linux下配置shell参数说明 前面已经讲到,变量名只能包含数字.字母和下划线,因为某些包含其他字符的变量有特殊含义,这样的变量被称为特殊变量. 例如,$ 表示当前Shell进程的ID,即pid ...

  9. LibOpenCM3(一) Linux下命令行开发环境配置

    目录 LibOpenCM3(一) Linux下命令行开发环境配置 本文使用 Linux 环境, 硬件为 STM32F103 系列开发板 LibOpenCM3 介绍 LibOpenCM3 是GPL协议( ...

随机推荐

  1. IPFS星际文件系统

    IPFS星际文件系统(InterPlanetary File System)是去中心化文件系统,本文介绍IPFS节点软件系统安装,环境搭建等简介入门教程,及学习如何使用ipfs-api和Node.js ...

  2. oracle查询相关语句

    1,查询表空间使用情况select a.a1 表空间名称,c.c2 类型,c.c3 区管理,b.b2/1024/1024 表空间大小M,(b.b2-a.a2)/1024/1024 已使用M,subst ...

  3. Docker 内核名字空间

    Docker 容器和 LXC 容器很相似,所提供的安全特性也差不多.当用 docker run 启动一个容器时,在后台 Docker 为容器创建了一个独立的名字空间和控制组集合. 名字空间提供了最基础 ...

  4. ELK学习记录一 :初识ELK

    ELK是elastic公司提供的一套完整的收集日志并分析展示的产品,分别表示Elasticsearch.Logstash和kibana. (官网截个图) 先来一段个人粗浅的认识: Elasticsea ...

  5. Java Web前端到后台常用框架介绍

    一.SpringMVC http://blog.csdn.net/evankaka/article/details/45501811 Spring Web MVC是一种基于Java的实现了Web MV ...

  6. MAC OS X下的Linux环境

    关键字: HomeBrew,好比Windows下的Cygwin 安装Homebrew 该si胜过macport ruby -e "$(curl -fsSL https://raw.githu ...

  7. android launcher 之踩到的坑

    需求: 1. 用android系统launcher 隐藏主菜单 所有应用显示在桌面 即workspace上: 2.隐藏launcher上方默认的google search: 3.切换一套launche ...

  8. iOS中的NSURLProtocol

    转自:iOS知识小集 NSURLProtocol类(注意,这个不是协议)经常用于实现一些URL Loading System相关的黑魔法.它可以拦截URL Loading System相关的网络请求, ...

  9. Picasso 完美兼容 OkHttp3.3,缓存优化两不误

    Tamic 专注移动开发!更多文章请关注http://www.jianshu.com/p/6241950f9daf csdn: http://blog.csdn.net/sk719887916/art ...

  10. 网络爬虫框架Scrapy简介

    作者: 黄进(QQ:7149101) 一. 网络爬虫 网络爬虫(又被称为网页蜘蛛,网络机器人),是一种按照一定的规则,自动地抓取万维网信息的程序或者脚本:它是一个自动提取网页的程序,它为搜索引擎从万维 ...