假设我使用以下行编写了一个程序:
int main(int argc, char** argv)
现在它通过检查argv
.
程序可以检测参数之间有多少空格吗?就像我在 bash 中输入这些:
ibug@linux:~ $ ./myprog aaa bbb
ibug@linux:~ $ ./myprog aaa bbb
环境是现代 Linux(如 Ubuntu 16.04),但我想答案应该适用于任何符合 POSIX 的系统。
假设我使用以下行编写了一个程序:
int main(int argc, char** argv)
现在它通过检查argv
.
程序可以检测参数之间有多少空格吗?就像我在 bash 中输入这些:
ibug@linux:~ $ ./myprog aaa bbb
ibug@linux:~ $ ./myprog aaa bbb
环境是现代 Linux(如 Ubuntu 16.04),但我想答案应该适用于任何符合 POSIX 的系统。
一般来说,没有。命令行解析由 shell 完成,它不会使未解析的行对被调用程序可用。实际上,您的程序可能是从另一个创建 argv 的程序执行的,该程序不是通过解析字符串,而是通过以编程方式构造参数数组。
谈论“论点之间的空格”是没有意义的;这是一个外壳概念。
shell 的工作是获取整行输入并将它们组成参数数组以启动命令。这可能涉及解析带引号的字符串、扩展变量、文件通配符和波浪号表达式等等。该命令以标准
exec
系统调用开始,该调用接受字符串向量。存在其他方法来创建字符串向量。许多程序通过预先确定的命令调用来分叉和执行它们自己的子进程——在这种情况下,永远不会有“命令行”这样的东西。类似地,当用户拖动文件图标并将其放在命令小部件上时,图形(桌面)外壳可能会启动一个进程 - 同样,没有文本行可以在“参数之间”包含字符。
就调用的命令而言,shell 或其他父/前体进程中发生的事情是私有的和隐藏的——我们只看到标准 C 指定
main()
可以接受的字符串数组。不,这是不可能的,除非空格是参数的一部分。
该命令访问数组中的各个参数(以一种或另一种形式,取决于编程语言),并且实际的命令行可以保存到历史文件中(如果在具有历史文件的 shell 中的交互式提示符下键入),但是从未以任何形式传递给命令。
Unix 上的所有命令最终都由
exec()
函数家族之一执行。它们采用命令名称和参数列表或数组。它们都没有在 shell 提示符下键入命令行。该system()
函数确实如此,但它的字符串参数稍后由 执行execve()
,它再次采用参数数组而不是命令行字符串。一般来说,这是不可能的,就像其他几个答案所解释的那样。
但是,Unix shell是普通程序(它们解释命令行并对其进行通配,即在执行&之前扩展命令)。请参阅有关shell 操作的说明。您可以编写自己的 shell(或者您可以修补一些现有的免费软件shell,例如GNU bash)并将其用作您的 shell(甚至是您的登录 shell,参见passwd(5)和shells(5))。
fork
execve
bash
例如,您可能有自己的 shell 程序将完整的命令行放在某个环境变量中(
MY_COMMAND_LINE
例如想象一下)-或使用任何其他类型的进程间通信将命令行从 shell 传输到子进程-。我不明白你为什么要这样做,但你可能会编写一个以这种方式运行的 shell(但我建议不要这样做)。
顺便说一句,一个程序可以由一些不是shell 的程序启动(但它执行fork(2)然后execve(2),或者只是
execve
在其当前进程中启动一个程序)。在那种情况下,根本没有命令行,您的程序可以在没有命令的情况下启动......请注意,您可能有一些(专门的)Linux 系统没有安装任何 shell。这是奇怪和不寻常的,但有可能。然后,您需要编写一个专门的init程序,根据需要启动其他程序 - 不使用任何 shell,而是通过执行
fork
&execve
系统调用。另请阅读操作系统:三个简单的部分,不要忘记这
execve
实际上总是一个系统调用(在 Linux 上,它们在syscalls(2)中列出,另请参见intro(2))重新初始化虚拟地址空间(以及其他一些事情)的过程。你总是可以告诉你的 shell 告诉应用程序是什么 shell 代码导致它们执行。例如,通过使用钩子在环境变量
zsh
中传递该信息(作为示例,您将在程序中使用):$SHELL_CODE
preexec()
printenv
getenv("SHELL_CODE")
所有这些都将执行
printenv
为:允许使用这些参数
printenv
检索导致执行的 zsh 代码。printenv
我不清楚你想用这些信息做什么。使用's
bash
时,最接近zsh
's的功能preexec()
将$BASH_COMMAND
在DEBUG
陷阱中使用它,但请注意,bash
它会在其中进行某种程度的重写(特别是重构一些用作分隔符的空格),并且适用于每个(嗯,一些)命令运行,而不是在提示符下输入的整个命令行(另请参见functrace
选项)。看看 shell 语言语法中的一些分隔符是如何被压缩到 1 中的,以及如何不总是将完整的命令行传递给命令。所以在你的情况下可能没用。
请注意,我不建议您这样做,因为您可能会将敏感信息泄露给每个命令,如下所示:
会将这个秘密泄露给
wc
和untrustedcmd
。当然,除了 shell 之外,你也可以对其他语言做这种事情。例如,在 C 中,您可以使用一些宏将执行命令的 C 代码导出到环境中:
例子:
看看 C 预处理器如何压缩一些空格,就像在 bash 案例中一样。在大多数(如果不是所有)语言中,分隔符中使用的空间量没有区别,因此编译器/解释器在这里对它们采取一些自由也就不足为奇了。
我将添加其他答案中缺少的内容。
不
查看其他答案
也许,有点
在程序中没有什么可以做的,但是当你运行程序时,可以在 shell 中做一些事情。
您需要使用引号。所以而不是
你需要做其中之一
这会将一个带有所有空格的参数传递给程序。两者之间有区别,第二个是字面量,就是它出现的字符串(除了
'
必须输入为\'
)。第一个将解释一些字符,但分成几个参数。有关更多信息,请参阅 shell 引用。所以不需要重写shell,shell设计者已经想到了。但是,由于它现在是一个参数,因此您将不得不在程序中进行更多的传递。选项 2
通过标准输入传入数据。这是将大量数据放入命令的正常方式。例如
或者
./myprog
Tell me what you want to tell me:
aaaa bbb
ctrl-d
(斜体为程序输出)