如何在不转义的情况下检测C语言argv中传入的*参数?
*参数 首先得给你讲清楚核心问题:当你直接敲./a.out *时,你的程序根本拿不到*这个字符——这是Unix/Linux shell的「文件名扩展(Globbing)」机制在搞事情。shell会先把*替换成当前目录下所有非隐藏的文件名,再把这些文件名作为参数传给你的程序。比如当前目录刚好有个文件叫1,那程序收到的argv[1]就是1,这和用户直接输入./a.out 1的效果完全一样,程序根本没法区分这两种情况。
那怎么实现你想要的「用户不用转义,直接输入*就能被检测到」?遗憾的是,在shell默认行为下这做不到——因为shell在程序启动前就把*处理掉了。不过我们可以换个思路来满足你的需求:
方案1:间接推测用户是否输入了*
如果用户输入的是*,shell会把它展开成多个参数(如果当前目录有多个文件),或者单个文件名(如果只有一个文件)。你可以通过以下逻辑来判断:
- 如果
argc > 2:说明shell把*展开成了多个文件名,这时候基本可以确定用户输入的是* - 如果
argc == 2:检查argv[1]是否是当前目录下的真实文件(用stat或access函数),如果是,那大概率是用户输入了*;但这种情况没法100%区分用户是输入了*还是刚好输入了那个文件名
给你一段示例代码:
#include <stdio.h> #include <string.h> #include <sys/stat.h> int main(int argc, char *argv[]) { if (argc > 2) { printf("推测用户输入了*(shell已将其展开为多个文件)\n"); } else if (argc == 2) { struct stat file_stat; // 检查argv[1]是否是存在的文件 if (stat(argv[1], &file_stat) == 0) { printf("用户可能输入了*,或者直接输入了文件名:%s\n", argv[1]); } else { // 如果不是文件,说明是用户传入的原始字符(比如*被转义/加引号了) if (strcmp(argv[1], "*") == 0) { printf("用户成功传入了*\n"); } else { printf("用户传入的参数是:%s\n", argv[1]); } } } else { printf("请传入参数\n"); } return 0; }
方案2:让用户临时关闭shell的Globbing
如果一定要让用户直接输入*就能被程序识别,可以让用户在执行命令前先关闭shell的文件名扩展功能,执行完再恢复:
set -f; ./a.out *; set +f
set -f会关闭shell的Globbing,这时候*会被直接传给程序,你就可以用strcmp(argv[1], "*") == 0来准确检测了。不过这种方式需要用户多敲几个命令,体验不算太好。
更实用的建议
其实在实际开发中,更通用的做法是告诉用户:如果要传入*作为参数,请用引号包裹(./a.out "*")或者转义(./a.out \*)——这是Unix/Linux环境下的通用规则,大部分用户都能理解。这样你的程序逻辑会非常简单,直接用strcmp判断argv[1]是否等于*就行,既准确又可靠。
内容的提问来源于stack exchange,提问作者bmw417

