如何将管道作为文件传递给 C 应用程序?
How do I pass pipe to a C app as a file?
我想做这样的事情:
nc localhost 1234 | myapp
但我希望 myapp 能够将命令第一部分传递的管道作为文件查看。
例如:
int main() {
File *fp;
fp = /* get pointer file which is the pipe passed as "nc localhost 1234" */
}
这可能吗?
谢谢。
从 BASH 开始,您可以使用 temporary fifo 功能:
myapp <( nc localhost 1234 )
在 C 中,如果你想将标准输入读取为 FILE 指针,那么只需使用 stdin
。
#include <stdio.h>
int main() {
FILE *fp;
fp = stdin;
}
如果您想直接在 C 中重定向自定义命令的输出,请使用 popen。
当您的程序作为管道的一部分启动时,
先前的过程通过管道传输到程序的标准输入。所以你可以
做:
int main(void)
{
char line[1024];
fgets(line, sizeof line, stdin);
printf("First line is: %s\n", line);
return 0;
}
在POSIX系统上,您可以使用isatty
检查文件描述符是否属于
指终端。例如:
#include <stdio.h>
#include <unistd.h>
int main(void)
{
if(isatty(STDIN_FILENO))
puts("stdin connected to terminal");
else
puts("piped data to stdin");
return 0;
}
程序的标准行为是从 stdin
读取并写入
stdout
。通过坚持这一点,您可以使用 shell 链接您的程序
管道 |
.
例如cat
如果没有传递文件则期望从标准输入读取
作为论据。 cat 的一个简单实现是:
int main(int argc, char **argv)
{
FILE *in = stdin;
if(argc == 2)
{
in = fopen(argv[1], "r");
if(in == NULL)
{
perror("fopen");
return 1;
}
}
int c;
while((c = fgetc(in)) != EOF)
fputc(c, stdout);
if(in != stdin)
fclose(in);
return 0;
}
作为一名程序员,我真的不在乎阅读 stdin
时是否
用户在终端中键入输入,或者输入是否通过管道传输。相同
写入 stdout
也是如此。作为用户,我知道 cat
这样的程序
当没有文件传递时从 stdin
读取并写入 stdout
。因为
我能做到的这种行为
$ echo "hi" | cat | sort
所以你也应该模仿这种行为。
当然,有时候知道是否涉及管道是件好事。例如
git diff
写入 stdout
时有颜色和无颜色
git diff | more
。在这种情况下,可以检查 stdout
的连接位置
到,但写入 stdout
的行为是相同的。
#include <stdio.h>
#include <unistd.h>
void print_colored_message(const char *msg)
{
printf("\x1b[31m%s\x1b[0m\n", msg);
}
void print_message(const char *msg)
{
if(isatty(STDOUT_FILENO))
print_colored_message(msg);
else
puts(msg);
}
int main(void)
{
print_message("Hello");
print_message("World");
return 0;
}
复制并粘贴此程序并以 ./test
执行一次,以 ./test | less
执行一次。
你会看到在第一个版本中你得到一个彩色输出,而在
第二个版本你不知道。保持不变的是输出是在
stdout
.
如果您不希望您的程序以这种方式链接,那么您必须告诉
您的用户,他们不应该在这样的链中使用您的程序。
您是否考虑过使用命名管道?它们就像管道一样,有方向性,但它们有名字。如果你想要两个方向,你可以做两个管道。你像这样制作管道:
mkfifo /dir/to_prog
mkfifo /dir/from_prog
然后一个程序的输出可以单独传输到第二个,管道的名称可以像普通文件名一样使用:
nc localhost 1234 > /dir/to_prog
myapp -i /dir/to_prog -o /dir/from_prog
cat < /dir/from_prog
除了这三个命令甚至可以在三个单独的 shell 中发出。 myapp.c 可能看起来像这样:
#include <stdio.h>
int
main(int argc, char *argv[])
{
int iFd, oFd, opt;
while (opt = getopt(argc, argv, "i:o:")) != -1) {
switch (opt) {
...
case 'i': iFd = open(optarg, O_RDONLY); break;
case 'o': oFd = open(optarg, O_WRONLY); break;
...
}
}
...
read(iFd, inBuf);
...
write(oFd, outBuf);
...
}
当我需要能够处理程序中的数据流时,由于某种原因还需要保留它自己的 STDIN 或 STDOUT,我已经使用过几次这种方法。如果您希望 myprog 能够从两个程序写入的管道中读取数据,那么唯一棘手的部分就来了,如:
cat afile > /dir/to_prog
cat anotherFile > /dir/to_prog
并让 myprog 能够读取这两个文件。问题是,当第一只猫退出时,它会关闭 /dir/to_prog,而 myprog 会将其读取为 EOF。许多程序将 EOF 解释为 "no more data time to quit!" 但在这种情况下,一旦第二只猫启动 myprog 将能够从 /dir/to_prog 读取更多数据,它只需要知道在看到 EOF 时不要放弃读取.当然,如果两个程序同时写入命名管道(或从中读取),它们的数据将随机交错。
我想做这样的事情:
nc localhost 1234 | myapp
但我希望 myapp 能够将命令第一部分传递的管道作为文件查看。
例如:
int main() {
File *fp;
fp = /* get pointer file which is the pipe passed as "nc localhost 1234" */
}
这可能吗?
谢谢。
从 BASH 开始,您可以使用 temporary fifo 功能:
myapp <( nc localhost 1234 )
在 C 中,如果你想将标准输入读取为 FILE 指针,那么只需使用 stdin
。
#include <stdio.h>
int main() {
FILE *fp;
fp = stdin;
}
如果您想直接在 C 中重定向自定义命令的输出,请使用 popen。
当您的程序作为管道的一部分启动时, 先前的过程通过管道传输到程序的标准输入。所以你可以 做:
int main(void)
{
char line[1024];
fgets(line, sizeof line, stdin);
printf("First line is: %s\n", line);
return 0;
}
在POSIX系统上,您可以使用isatty
检查文件描述符是否属于
指终端。例如:
#include <stdio.h>
#include <unistd.h>
int main(void)
{
if(isatty(STDIN_FILENO))
puts("stdin connected to terminal");
else
puts("piped data to stdin");
return 0;
}
程序的标准行为是从 stdin
读取并写入
stdout
。通过坚持这一点,您可以使用 shell 链接您的程序
管道 |
.
例如cat
如果没有传递文件则期望从标准输入读取
作为论据。 cat 的一个简单实现是:
int main(int argc, char **argv)
{
FILE *in = stdin;
if(argc == 2)
{
in = fopen(argv[1], "r");
if(in == NULL)
{
perror("fopen");
return 1;
}
}
int c;
while((c = fgetc(in)) != EOF)
fputc(c, stdout);
if(in != stdin)
fclose(in);
return 0;
}
作为一名程序员,我真的不在乎阅读 stdin
时是否
用户在终端中键入输入,或者输入是否通过管道传输。相同
写入 stdout
也是如此。作为用户,我知道 cat
这样的程序
当没有文件传递时从 stdin
读取并写入 stdout
。因为
我能做到的这种行为
$ echo "hi" | cat | sort
所以你也应该模仿这种行为。
当然,有时候知道是否涉及管道是件好事。例如
git diff
写入 stdout
时有颜色和无颜色
git diff | more
。在这种情况下,可以检查 stdout
的连接位置
到,但写入 stdout
的行为是相同的。
#include <stdio.h>
#include <unistd.h>
void print_colored_message(const char *msg)
{
printf("\x1b[31m%s\x1b[0m\n", msg);
}
void print_message(const char *msg)
{
if(isatty(STDOUT_FILENO))
print_colored_message(msg);
else
puts(msg);
}
int main(void)
{
print_message("Hello");
print_message("World");
return 0;
}
复制并粘贴此程序并以 ./test
执行一次,以 ./test | less
执行一次。
你会看到在第一个版本中你得到一个彩色输出,而在
第二个版本你不知道。保持不变的是输出是在
stdout
.
如果您不希望您的程序以这种方式链接,那么您必须告诉 您的用户,他们不应该在这样的链中使用您的程序。
您是否考虑过使用命名管道?它们就像管道一样,有方向性,但它们有名字。如果你想要两个方向,你可以做两个管道。你像这样制作管道:
mkfifo /dir/to_prog
mkfifo /dir/from_prog
然后一个程序的输出可以单独传输到第二个,管道的名称可以像普通文件名一样使用:
nc localhost 1234 > /dir/to_prog
myapp -i /dir/to_prog -o /dir/from_prog
cat < /dir/from_prog
除了这三个命令甚至可以在三个单独的 shell 中发出。 myapp.c 可能看起来像这样:
#include <stdio.h>
int
main(int argc, char *argv[])
{
int iFd, oFd, opt;
while (opt = getopt(argc, argv, "i:o:")) != -1) {
switch (opt) {
...
case 'i': iFd = open(optarg, O_RDONLY); break;
case 'o': oFd = open(optarg, O_WRONLY); break;
...
}
}
...
read(iFd, inBuf);
...
write(oFd, outBuf);
...
}
当我需要能够处理程序中的数据流时,由于某种原因还需要保留它自己的 STDIN 或 STDOUT,我已经使用过几次这种方法。如果您希望 myprog 能够从两个程序写入的管道中读取数据,那么唯一棘手的部分就来了,如:
cat afile > /dir/to_prog
cat anotherFile > /dir/to_prog
并让 myprog 能够读取这两个文件。问题是,当第一只猫退出时,它会关闭 /dir/to_prog,而 myprog 会将其读取为 EOF。许多程序将 EOF 解释为 "no more data time to quit!" 但在这种情况下,一旦第二只猫启动 myprog 将能够从 /dir/to_prog 读取更多数据,它只需要知道在看到 EOF 时不要放弃读取.当然,如果两个程序同时写入命名管道(或从中读取),它们的数据将随机交错。