C 传递包含“!!”的字符串时argv的奇怪行为&引用;
我已经编写了一个小程序,从C 传递包含“!!”的字符串时argv的奇怪行为&引用;,c,bash,quotes,argv,C,Bash,Quotes,Argv,我已经编写了一个小程序,从*argv[]获取一些输入参数并打印它们。在几乎所有的用例中,我的代码都工作得非常好。只有当我在要作为参数传递的字符串末尾使用多个感叹号时,才会出现问题 这项工作: ./program -m "Hello, world!" 这不起作用: ./program -m "Hello, world!!!!" ^^如果我这样做,程序输出要么是该字符串的两倍,要么是我在./program之前输入的命令 然而,我完全不明白的是:奇怪的是,以下几点确实有效: ./program -
*argv[]
获取一些输入参数并打印它们。在几乎所有的用例中,我的代码都工作得非常好。只有当我在要作为参数传递的字符串末尾使用多个感叹号时,才会出现问题
这项工作:
./program -m "Hello, world!"
这不起作用:
./program -m "Hello, world!!!!"
^^如果我这样做,程序输出要么是该字符串的两倍,要么是我在./program之前输入的命令
然而,我完全不明白的是:奇怪的是,以下几点确实有效:
./program -m 'Hello, world!!!!'
^^输出正好是
Hello, world!!!!
。。。如你所愿
因此,我的问题是:
- 为什么在字符串中使用多个感叹号时会出现这种奇怪的行为
- 据我所知,在C语言中,字符串使用
,单字符使用”
。那么,为什么我在使用”
时得到了预期的结果,而在我看来,当我应该使用''
时却没有得到预期的结果呢''
- 我的代码中是否有错误,或者我需要更改什么才能输入任何字符串(无论是否使用、使用什么以及使用多少标点符号),并准确打印该字符串
// this is a simplified example that, in essence, does the same
// as my (significantly longer) code
int main(int argc, char* argv[]) {
char *msg = (char *)calloc(1024, sizeof(char));
printf("%s", strcat(msg, argv[2])); // argv[1] is "-m"
free(msg);
}
我已经尝试先将
argv[2]
的内容复制到char*
缓冲区中,然后在缓冲区中附加一个'\0'
,这没有改变任何内容。shell以双引号字符串进行扩展。如果您阅读(假设您使用Bash,这是大多数Linux发行版的默认版本),那么如果您查看,您将看到代码>意味着
请参阅前面的命令
所以双引号字符串中的code>将扩展到上一个命令,两次
这种扩展不适用于单引号字符串
因此,问题不在程序内部,而是由调用程序的环境(shell)造成的。这与代码无关,而是与启动程序的shell有关
在大多数shell中,
是上次运行的命令的简写形式。当您使用双引号时,shell允许(以及变量替换等)在字符串中,因此当您放入
在双引号字符串中,它替换最后一次运行的命令
这对你的程序来说意味着所有这些都发生在你的程序执行之前,因此除了检查传入的字符串是否有效之外,程序没有什么可以做的
相反,当您使用单引号时,shell不进行任何替换,字符串未经修改就传递给程序
所以你需要用单引号来传递这个字符串。如果用户不希望发生任何替换,他们需要知道这一点。另一种方法是创建一个包装器shell脚本,提示用户输入字符串,然后该脚本随后将使用正确的参数调用您的程序。除了提供的答案之外,您应该记住echo是您的shell朋友。如果您在命令前面加上“echo”,您将看到shell实际发送给脚本的内容
echo ./program -m "Hello, world!!!!"
这会给你一些奇怪的感觉,可能会帮助你朝着正确的方向前进。为什么printf(“%s”,strcat(msg,argv[2])
而不是printf(“%s”,argv[2])
?你需要逃离这个空间。而且,calloc()
这也没什么意义。只是charmsg[1024]
非常好。使用单个qoutes时,字符串按原样传递。这与argv
或编程语言无关,但与shell@Michael沃尔兹:因为我正在用msg创建一个更长的字符串。将argv的内容附加到它只是我完整代码中许多步骤的第一步。很抱歉没有在前面说明。感叹号是shell的特殊字符(可能是bash
)。如果它没有放在单引号中,shell将解释
并将其替换为其他命令(历史记录中的上一个命令)。您的程序工作正常,它在命令行中打印它从shell接收到的内容。@ci7i2en4:1)语法错误是在扩展过程中创建的bash语法错误,在这种情况下,您的程序甚至没有启动。2)您的程序应该负责验证输入值,但您不能“撤消”bash完成的扩展。您应该做的事情是:检查argc
是否具有有效长度,检查参数是否合理,然后可能会显示一条包含使用信息的错误消息。我明白了,谢谢!这就给我留下了一个问题:有没有办法确保我的程序的用户仍然可以使用“Something!!!!”作为输入参数而不经历这种行为?(不管他们使用什么外壳)@ci7i2en4这取决于你的用户。也许他们希望这种扩展发生,也许不是。@ci7i2en4,在Bash中,set+o histexpand
或set+H
禁用历史扩展。其他shell可能有其他设置。我想指出,任何改变shell预期行为的解决方案都可能是一个坏主意。用户应该知道如何在他们使用的任何shell中发送输入。^^^此外,这只会改变my bash的行为。如果其他人在他们的shell中运行我的程序,他们仍然会经历历史扩展…echo
实际上是一个非常糟糕的工具选择用于此用途--echo“hello world”
和echo“hello”“world”
毕竟具有完全相同的输出,尽管有不同的命令,但请考虑:<代码> PrimtAgSARS():Prtff’%q’“$@”;Prtff’\n’;} /Case>——此后,<代码> PrtPr.ARGS/程序-M“Hello,World!!!”!<代码>将以一种方式发出参数,即使在<代码> Engule>代码>出错的情况下,它们的解释也不含糊。