Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/bash/17.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 传递包含“!!”的字符串时argv的奇怪行为&引用;_C_Bash_Quotes_Argv - Fatal编程技术网

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发行版的默认版本),那么如果您查看,您将看到
意味着

请参阅前面的命令

所以
将扩展到上一个命令,两次

这种扩展不适用于单引号字符串


因此,问题不在程序内部,而是由调用程序的环境(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>代码>出错的情况下,它们的解释也不含糊。