我有这个外壳,我正在为一个夏季项目编写。例如,我正在尝试解析命令行,
如果我打电话
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/