我在这里,我想通过用C POPEN传递一个字符串两难,但它保持字符串中的双引号。 该字符串的内容如下:
ssh %s@%s grep -c \"%s\" %s%s
我需要那么它从一个远程系统上的日志里grep,返回计数为它运行此命令。 我通过字符串传递不同的参数,所以它产生的用户名和密码,以及搜索字符串和目标。 然而,搜索字符串包含空格字符分隔多个词,所以我需要在双引号不变,以便它正确解析出所搜索的字符串。 然而,到目前为止POPEN已经从字符串剥离双引号因此搜索没有完成。 我不知道的另一种方式进行远程ssh命令,或保持双引号中的语句。 有任何想法吗?
谢谢!
*编辑:这是我使用生成的字符串还有POPEN命令的完整的sprintf语句。
sprintf(command, "ssh %s@%s grep -c \"%s\" %s%s", user, server, search, path, file);
fd = popen(command, "r");
popen
叉该高管以2个参数的壳儿: -c
,你传递给popen方法的命令字符串。 因此,需要进行转义所以外壳确实与他们正确的事你传递有意义的外壳任何字符。 在你的情况,你需要的壳,以保持"
字符,以便远程shell会得到他们,这是最简单的包装做'
身边的报价:
sprintf(command, "ssh %s@%s grep -c '\"%s\"' %s%s", ...
但是,如果你的搜索字符串不包含任何这只会工作'
或"
字符-如果有的话,你需要做一些更复杂的逃逸你也可以使用反斜杠。
sprintf(command, "ssh %s@%s grep -c \\\"%s\\\" %s%s", ...
但如果你的搜索字符串有引号或多个连续的空格或其他空白状突片诠释它,则会失败。 为了应对所有的情况下,你需要先插入反斜杠在搜索字符串的所有相关charaters之前,加上'
对应对疼痛:
// allocate 4*strlen(search)+1 space as escaped_search
for (p1 = search, p2 = escaped_search; *p1;) {
if (*p1 == '\'') *p2++ '\'';
if (strchr(" \t\r\n\"\\'{}()<>;&|`$", *p1))
*p2++ = '\';
if (*p1 == '\'') *p2++ '\'';
*p2++ = *p1++; }
*p2 = '\0';
sprintf(command, "ssh %s@%s grep -c '%s' %s%s", user, server, escaped_search, ...
问题不在于与sprintf
,而不是与popen
。 问题是,调用外壳ssh
。 这是条你报价的外壳。
你可以简单地打开一个终端并手动尝试。 你会看到,
ssh user@server grep -c "search string" path
按预期如果搜索字符串包含空格不起作用。 壳牌消耗的报价,从而使最终grep
接收不带引号的命令行,并错误地解释它。
如果你想在报价坚持,你必须逃脱他们的壳。 您要执行的命令是
ssh user@server grep -c \"search string\" path
要使用形成这样的字符串sprintf
你也有逃脱"
和\
字符(C编译器)这意味着\"
变成\\\"
。最后的格式行如下
sprintf(command, "ssh %s@%s grep -c \\\"%s\\\" %s%s", user, server, search, path, file);
当然,这仍然可以在多德的回答中提到的其他问题的影响。
一些实验后,这似乎很可能是你所需要的:
snprintf(command, sizeof(command), "ssh %s@%s grep -c \\\"%s\\\" %s%s",
username, hostname, search_string, directory, file);
你需要多个反斜杠反斜杠,因为多解释都参与。
- C编译器:它把3为一个反斜线的每个序列中的第一两个反斜杠。 第三个反斜杠转义双引号,嵌入在双引号
command
字符串。 命令字符串,然后包含\"
两次。 - 还有一个过程处理反斜杠,这是一个有点棘手,决定它在哪里,但他们需要得到正确的结果,如图实验。
工作守则 - 远程执行,正确的结果
下面是一些演示代码工作。 当地的计划被称为pop
。 在那里一切都是硬连线,因为我很懒(但我被改写的远程主机名和我实际上测试的一个比较)。 该方案/u/jleffler/linux/x86_64/bin/al
列出了它的参数如收到,每行一个。 我觉得像这样的情况下非常有用的工具。 需要注意的是参数al
都经过精心双位制作时的参数作为一个VS多处理显现。
$ ./pop
Command: <<ssh jleffler@remote.example.com /u/jleffler/linux/x86_64/bin/al \"x y z\" \"pp qq rr\">>
jleffler@remote.example.com's password:
Response: <<x y z>>
Response: <<pp qq rr>>
$
码
#include <stdio.h>
#include <string.h>
int main(void)
{
char command[512];
char const *arg1 = "x y z";
char const *arg2 = "pp qq rr";
char const *cmd = "/u/jleffler/linux/x86_64/bin/al";
char const *hostname = "remote.example.com";
char const *username = "jleffler";
snprintf(command, sizeof(command), "ssh %s@%s %s \\\"%s\\\" \\\"%s\\\"",
username, hostname, cmd, arg1, arg2);
printf("Command: <<%s>>\n", command);
FILE *fp = popen(command, "r");
char line[512];
while (fgets(line, sizeof(line), fp) != 0)
{
line[strlen(line)-1] = '\0';
printf("Response: <<%s>>\n", line);
}
pclose(fp);
return(0);
}
变体1 - 远程执行,错误结果
$ ./pop1
Command: <<ssh jleffler@remote.example.com /u/jleffler/linux/x86_64/bin/al "x y z" "pp qq rr">>
jleffler@remote.example.com's password:
Response: <<x>>
Response: <<y>>
Response: <<z>>
Response: <<pp>>
Response: <<qq>>
Response: <<rr>>
$
码
#include <stdio.h>
#include <string.h>
int main(void)
{
char command[512];
char const *arg1 = "x y z";
char const *arg2 = "pp qq rr";
char const *cmd = "/u/jleffler/linux/x86_64/bin/al";
char const *hostname = "remote.example.com";
char const *username = "jleffler";
snprintf(command, sizeof(command), "ssh %s@%s %s \"%s\" \"%s\"",
username, hostname, cmd, arg1, arg2);
printf("Command: <<%s>>\n", command);
FILE *fp = popen(command, "r");
char line[512];
while (fgets(line, sizeof(line), fp) != 0)
{
line[strlen(line)-1] = '\0';
printf("Response: <<%s>>\n", line);
}
pclose(fp);
return(0);
}
变体2 - 本地执行,(不同的)错误结果
$ ./pop2
Command: <<al jleffler@remote.example.com /u/jleffler/linux/x86_64/bin/al \"x y z\" \"pp qq rr\">>
Response: <<jleffler@remote.example.com>>
Response: <</u/jleffler/linux/x86_64/bin/al>>
Response: <<"x>>
Response: <<y>>
Response: <<z">>
Response: <<"pp>>
Response: <<qq>>
Response: <<rr">>
$
当地壳不需要双引号前反斜杠; 事实上,增加它得到它错了。
码
#include <stdio.h>
#include <string.h>
int main(void)
{
char command[512];
char const *arg1 = "x y z";
char const *arg2 = "pp qq rr";
char const *cmd = "/u/jleffler/linux/x86_64/bin/al";
char const *hostname = "remote.example.com";
char const *username = "jleffler";
snprintf(command, sizeof(command), "al %s@%s %s \\\"%s\\\" \\\"%s\\\"",
username, hostname, cmd, arg1, arg2);
printf("Command: <<%s>>\n", command);
FILE *fp = popen(command, "r");
char line[512];
while (fgets(line, sizeof(line), fp) != 0)
{
line[strlen(line)-1] = '\0';
printf("Response: <<%s>>\n", line);
}
pclose(fp);
return(0);
}
变体3 - 本地执行,正确的结果
$ ./pop3
Command: <<al jleffler@remote.example.com /u/jleffler/linux/x86_64/bin/al "x y z" "pp qq rr">>
Response: <<jleffler@remote.example.com>>
Response: <</u/jleffler/linux/x86_64/bin/al>>
Response: <<x y z>>
Response: <<pp qq rr>>
$
码
#include <stdio.h>
#include <string.h>
int main(void)
{
char command[512];
char const *arg1 = "x y z";
char const *arg2 = "pp qq rr";
char const *cmd = "/u/jleffler/linux/x86_64/bin/al";
char const *hostname = "remote.example.com";
char const *username = "jleffler";
snprintf(command, sizeof(command), "al %s@%s %s \"%s\" \"%s\"",
username, hostname, cmd, arg1, arg2);
printf("Command: <<%s>>\n", command);
FILE *fp = popen(command, "r");
char line[512];
while (fgets(line, sizeof(line), fp) != 0)
{
line[strlen(line)-1] = '\0';
printf("Response: <<%s>>\n", line);
}
pclose(fp);
return(0);
}
正如其他人在这里解释,引用有时候会很麻烦。
为了避免过多的引用只是管的命令到SSH的标准输入。 就像下面的bash代码:
ssh remote_host <<EOF
grep -c "search string" path
EOF