c - 解析 Shell 的命令行参数

标签 c argv execv

我有这个外壳,我正在为一个夏季项目编写。例如,我正在尝试解析命令行,

如果我打电话

ls -l

我需要解析
-l

部分。

所以我可以将它传递给 execv 中使用的参数 vector .我知道我正在正确解析它,但由于某种原因,找不到目录。我可能错过了什么吗?下面是我的代码。

最佳答案

虽然 strtok标准库函数可以有用,你需要注意它的接口(interface)的缺点,这基本上是一个粗心的陷阱。
在这个程序中,您似乎偶然发现了 strtok 最常见的两个问题。界面。请重读man strtok仔细结合这个答案,以免将来陷入这些问题。此外,请勿使用 strtok作为一个好的界面设计的例子。相反,将其用作应避免的模型:
隐藏的全局状态strtok对保存在静态变量中的字符串指针进行操作。无论何时调用 strtok使用非 NULL 第一个参数时,它首先将此静态变量的值重置为该字符串。在每次通话结束时 strtok ,它将其静态变量设置为下一次扫描应该开始的地址,就在它刚刚找到的 token 之后。
整个程序中只有一个静态变量的实例,所以不能交错strtok扫描两个不同的字符串。更糟糕的是,您不能调用本身调用 strtok 的函数。在 strtok 内扫描字符串,因为函数内部的调用将重置 strtok状态。
这意味着当您拥有多个 strtok 时,您必须小心。在程序中扫描。在您的情况下,在初始化命名错误的变量 env 之后:

token = strtok(env, ":");
您使用 strtok将您的输入命令分成名称错误的变量 argv :
argv = strtok(buf_copy, " ");
所以当你以后想要找到 env 的下一个组件时:
token = strtok(NULL, ":");
strtok的状态不再指向 env ;相反,它指向 buf_copy (并且,根据您的特定输入,在 buf_copy 中找不到更多标记的位置)。
修改输入参数strtok 的第一个参数是 char* ,而不是 const char* .
通常,如果库函数有字符串参数,则该参数应声明为 const char*除非函数打算修改字符串。或者,换一种说法,const char*声明是一个 promise ,不会尝试修改参数,如果没有做出 promise ,这可能是有充分理由的。
而且,确实,如果您阅读 strtok的文档中,您将看到它通过用 NUL 字符覆盖一些分隔符来显式地修改其输入字符串。这具有将原始字符串永久划分为单独标记的效果。有时这很好,但如果你想在将来再次引用字符串的原始值,它会给你带来很多麻烦。通常你会发现自己复制了原始字符串以便调用 strtok。在上面。 (这通常是糟糕的程序设计的征兆,或者表明 strtok 并不是真正适合用于解析的工具。)
在这个特定的程序中,陷阱是 getenv()不返回环境变量值的副本。它直接返回一个指向环境变量表的指针。虽然 getenv 的返回类型是 char* ,这可能会让您相信修改值是可以的,但 C 标准明确告诉您不要:

The string pointed to shall not be modified by the program


不幸的是,getenv 的 Linux 手册页中没有此禁令。 ,但该手册页确实注意到 getenv给你一个指向环境表的指针。如果你修改 getenv 返回的字符串,很有可能(尽管不能保证)随后调用 getenv对于相同的环境变量,将检索修改后的值。
这正是你所做的:因为你让 strtok松开 getenv(PATH) 返回的字符串,随后调用 getenv(PATH)将看到在第一个冒号处截断的值。

关于c - 解析 Shell 的命令行参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56845395/

相关文章:

c - 使用 fscanf 读入指针时出现段错误(核心已转储)

c - 为什么 `execv` 不能使用从 char** 到 char* const* 的隐式转换?

c - 用 C 写一个 shell,不返回任何东西

c - 如何将 char ** 转换为 c 中的 char *[]?

C 函数通过参数之一返回结构数据

c - 在 OSX 上为 ICU 核心生成或查找 C 头文件

python - 如何在 Linux 中用 C 语言执行 Python 程序

c - 在c中,要求扫描点后的1位数字并得到乱码

c - 有没有来自标准输入的东西?

c++ - Argv[] 未注册参数