【问题标题】:argv: Sanitizing wildcardsargv:清理通配符
【发布时间】:2015-01-21 19:06:47
【问题描述】:

我正在研究 K&R C 书中的一个示例,它要求您构建一个 RPN 计算器,该计算器通过命令行参数获取输入。我的解决方案本质上是遍历给定的参数并吐出答案,但我注意到了一些事情:

如果我要给出不带单引号的乘法字符(星号)'*',gcc 会假定它是通配符输入,所以我的输入是

$./rpn 5 10 *

给我一​​个输出

read 5
read 10
read rpn
read rpn.c
= 0

用单引号将星号括起来可以解决问题

$./rpn 5 10 '*'
read 5
read 10
read *
= 50

我的问题是有没有办法清理输入,以便我的程序不需要用单引号括起星号,或者这种行为是由更基本的东西引起的(例如 Linux/POSIX/UNIX 二进制执行和参数处理)?

【问题讨论】:

  • 全部与shell有关;与 C 编译器完全无关。为了演示,尝试编写一个小程序:#include <unistd.h>int main(void) { char *args[] = { "./rpn", "5", "10", "*", 0 }; execv(args[0], args); return -1; }。 shell 通常扩展*;这样可以避免使用 shell,因此不会发生扩展。
  • GCC 什么都不知道。 Shell 是向您的程序提供输入的那个。
  • @JonathanLeffler @self 我试过了,就像你说的那样;它执行并输出正确的答案。正如下面的@IgnacioVazquez-Abrar 所述,这是由 bash 将 * 通配符 glob 扩展为当前目录中所有文件的列表引起的。我当然应该更加注意外壳。
  • 这是一个标准的陷阱; * 是唯一常用的算术运算符,它也是一个 shell 元字符。如果您在中缀计算器中使用括号(根据定义,您不会在 RPN 计算器中使用括号),那么它们也会妨碍您,因为它们对 shell 也有特殊含义。
  • 如果您真的不希望您的 Bash 不进行路径名扩展,请以 bash -f 开头或在正在运行的 Bash 中键入 set -f(并使用 set +f 撤消)。

标签: c linux shell gcc glob


【解决方案1】:

shell 在执行程序之前正在扩展 glob。您引用 glob 不是因为 GCC,而是因为 shell。如果您不希望这种行为,请使用不支持 glob 的 shell。

【讨论】:

  • 我明白了。如果开发人员在不考虑 shell 的情况下对开发人员正在编程的输入不太小心,这可能是导致未定义行为的一个非常常见的原因。我想这个例子有一个隐藏的教训,那就是解释经常被忽视的执行层。
  • 在我看来,它并没有真正被忽视。你只需要知道你的工具。
  • 这不是“未定义的行为”。它的定义非常明确;这不是你想要的。
  • @duskwuff 你是对的。我想一个更好的词是“无意的”。
【解决方案2】:

输入为

$./rpn "5 10 *" 

"" 和程序中的所有参数,您将获得argv[1] 下的所有参数,然后通过空格分隔解析该字符串。

通过这种方式,您确实需要以特殊方式处理任何通配符/特殊字符。

【讨论】:

  • 另外,您将所有字符都视为需要特别注意……并使rpn 程序复杂化。
  • 当任何空间进入任何文件名/路径时,由此类命令行参数给出,它会在 linux 和 windows 中产生问题,因此另一种处理这些事情的方法是将它们视为特殊的跨度>
  • @Mr.32 如果情况不同,我通常会同意你的看法,但是该练习特别要求将输入作为离散的命令行参数进行处理。
猜你喜欢
  • 1970-01-01
  • 2018-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-01-04
相关资源
最近更新 更多