1.基本概念
在 linux(及其他类 unix 系统)中,命令行参数是执行命令或程序时,跟随在命令名称之后的额外信息。它们的作用是向程序传递具体指令、配置选项或操作对象,让程序根据参数的不同执行不同的行为。
1.1.参数的组成
一个完整的命令行通常由三部分构成:
- 命令名称 [选项] [参数值]
- 命令名称:要执行的程序(如 ls、cp、grep 等)。
- 选项(options):用于调整命令的行为(如是否显示详细信息、是否忽略错误等)。
- 参数值(arguments):命令操作的对象(如文件名、路径、文本内容等)。
例如:
ls -l /home/user #ls 是命令名称; #-l 是选项(表示 “以详细列表形式显示”); #/home/user 是参数值(表示要列出的目录)。
1.2选项(options)的分类
选项是命令行参数中最灵活的部分,用于控制命令的细节行为,主要分为两类:
1.2.1 短选项(short options)
格式 | 以单个连字符 - 开头,后跟一个字母(或数字)。 |
特点 | 简洁,可组合使用。 |
示例:
ls -l:-l 表示 “详细列表”; ls -a:-a 表示 “显示隐藏文件”; ls -la:组合 -l 和 -a,即 “详细列表 + 显示隐藏文件”。
1.2.2 长选项(long options)
格式 | 以两个连字符 -- 开头,后跟完整单词(或多个单词,用连字符连接)。 |
特点 | 语义明确,便于理解,通常与短选项功能对应。 |
示例:
ls --all:与 -a 功能相同(显示隐藏文件); ls --format=long:与 -l 功能相同(详细列表); rm --force:与 -f 功能相同(强制删除,不提示)。
1.2.3 带值的选项
部分选项需要跟随具体的值(如配置路径、设置模式等),短选项和长选项都可能需要:
短选项 | 值通常紧跟选项(可空格分隔,也可直接拼接)。 |
例如:
grep -i "hello"(-i 表示 “忽略大小写”,值是要搜索的文本 "hello")。
长选项 | 值通常用 = 连接(也可用空格)。 |
例如:
ls --color=auto(--color 选项的值为 auto,表示 “自动根据终端是否支持颜色显示”)。
1.3参数值(arguments)
参数值是命令直接操作的对象,不需要前缀符号(- 或 --),常见类型包括:
参数值类型 | 描述 | 示例 |
---|---|---|
文件名 | 命令操作的具体文件 | file.txt(如 cat file.txt 中的 file.txt) |
目录路径 | 命令操作的目录位置 | /tmp(如 cd /tmp 中的 /tmp) |
文本内容 | 命令处理的具体文本 | "error"(如 grep "error" log.txt 中的 "error") |
数字 | 命令使用的数值参数 | 10(如 head -n 10 file.txt 中的 10,表示显示前 10 行) |
注意:如果参数值本身以 - 开头(如文件名 -test.txt),命令可能会误认为是选项,此时需用 -- 分隔选项和参数,例如:
rm -- -test.txt(-- 告诉 rm 后面的内容都是参数,不是选项)
1.4特殊符号参数
在命令行中,有一些特殊符号被约定为特定含义的参数:
- -(连字符)
通常代表 “标准输入(stdin)” 或 “标准输出(stdout)”,用于命令间的数据传递。
示例 1:cat -(从键盘输入读取内容,直到按 ctrl+d 结束); 示例 2:tar -cvf - /home | gzip > backup.tar.gz(- 表示将 tar 的输出作为 gzip 的输入)。
- --(双连字符)
用于明确分隔选项和参数,避免参数被误解析为选项。
如前面提到的: rm -- -test.txt
2.main函数
在 c/c++ 程序中,main函数是程序的入口点,它可以接收命令行参数,使程序能在启动时获取外部输入。main函数的参数有固定的标准形式,用于处理命令行传递的参数。
main 函数的参数形式
- 标准的main函数参数声明如下:
int main(int argc, char *argv[]) { // 程序逻辑 return 0; }
参数 | 类型 | 含义 |
---|---|---|
argc | int | 命令行参数的总个数(包含程序名本身) |
argv | char *[] 或 char ** | 字符串数组,存储具体的命令行参数 |
2.1示例
#include <stdio.h> #include <sys/types.h> #include <unistd.h> int main(int argc,char *argv[]) { for(int i=0;i<argc;i++) { printf("argv[%d]->%s\n",i,argv[i]); } return 0; }
- 运行结果:
想要验证 null 可以 修改i<argc成argv[i]
#include <stdio.h> #include <sys/types.h> #include <unistd.h> int main(int argc,char *argv[]) { for(int i=0;argv[i];i++)//修改i<argc成argv[i] { printf("argv[%d]->%s\n",i,argv[i]); } return 0; }
2.3模拟命令
我们来模拟一下ls命令:
#include <stdio.h> #include <sys/types.h> #include <unistd.h> #include <string.h> int main(int argc,char *argv[]) { if(argc!=2) { printf("usage: %s -[a,b,c,d]\n",argv[0]); } else if(strcmp(argv[1],"-a")==0) { printf("this is fiction 1!\n"); } else if(strcmp(argv[1],"-b")==0) { printf("this is fiction 2!\n"); } else if(strcmp(argv[1],"-c")==0) { printf("this is fiction 3!\n"); } else if(strcmp(argv[1],"-d")==0) { printf("this is fiction 4!\n"); } else printf("no this fiction\n"); return 0; }
ls等命令和我们写的程序一样,同一个程序给予不同的参数,执行不同的功能。
2.4小结
命令行中用空格分隔参数,若参数本身包含空格,需用引号(单引号或双引号)括起来
- argc的值至少为 1,因为argv[0]始终存在
- argv数组中的字符串都是以 null 结尾的 c 风格字符串
- c++ 中还可以使用char **argv形式,与char *argv[ ]等价
3.参数化的意义
3.1为什么要有命令行参数?
本质:命令行参数本质是交给我们程序的不同的选型,用来定制不同的程序功能。命令中会携带很多的选项。
3.2参数如何传递参数给main函数的
1.父进程的数据能被子进程看见
#include <stdio.h> #include <sys/types.h> #include <unistd.h> #include <string.h> int g_val = 100000; int main() { printf("i am father process, pid: %d, ppid: %d, g_val: %d\n", getpid(), getppid(), g_val); sleep(5); pid_t id = fork(); if (id == 0) { // child while (1) { printf("i am child process, pid: %d, ppid: %d, g_val: %d\n", getpid(), getppid(), g_val); sleep(1); } } else { // father while (1) { printf("i am father process, pid: %d, ppid: %d, g_val: %d\n", getpid(), getppid(), g_val); sleep(1); } } }
2.命令行中启动的程序都会变成进程,其实都是 bash 的子程序。
- 启动程序
- vim命令 (本质也是一种程序)
- 因此我们得知参数是由父进程 bash 参数传递的。
4.总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持代码网。
发表评论