如何对管道中的数据调用 UNIX 排序命令
How to call UNIX sort command on data in pipe
我正在创建一个 C 程序,并使用它在单独的分叉进程之间设置管道以进行进程间通信。
第一个进程已将我需要的数据写入管道。
但是,随着第二个进程从管道读取,我试图执行该进程以成为 UNIX 排序命令。我想以某种方式对管道中的数据调用排序。
如何在管道上调用排序?在命令行上,我可以通过提供要排序的文件名作为命令行参数进行排序,例如"sort -r MyFileToSort"。我知道管道本质上被认为是文件,但它们仅由文件描述符描述,据我所知,sort 不知道如何处理 fd。
感谢任何 help/feedback
在这种情况下,您根本不需要传递 sort
任何参数来指定输入源或输出接收器。相反,在 exec
ing 它之前,您应该根据需要将管道的文件描述符附加到其标准输入(FD 0,如果从管道接收数据)或标准输出(FD 1,如果将数据写入管道)。
请参阅 dup2()
调用,它允许您为此目的设置要将 FD 复制到的目标。正如@JonathanLeffler 指出的那样,您需要确保在调用 exec 之前关闭原始 FD(在将它们复制到您想要的数字之后)。
由于您在评论中阐明了您的目标是写入文件,因此您可以在调用 exec
之前将 FD 1 附加到该目标文件,并将 FD 0 附加到包含输入的管道。
int p[2];
if (pipe(p) != 0) ...report error and do not continue...
pid_t pid = fork();
if (pid < 0) ...report error, close pipe descriptors, and do not continue...
if (pid == 0)
{
/* Child - becomes sort */
dup2(p[0], 0);
close(p[0]);
close(p[1]);
int fd = open("output-file", O_CREAT | O_EXCL | O_WRONLY, 0644);
if (fd < 0) ...report error and exit...
dup2(fd, 1);
close(fd);
execlp("sort", "sort", (char *)0);
...report error and exit...
}
else
{
/* Parent - writes data to sort */
close(fd[0]);
...write data to fd[1]...
close(fd[1]);
int status;
int corpse;
while ((corpse = wait(&status)) > 0 && corpse != pid)
...consider reporting which child died...
...consider reporting sort status...
...continue with the rest of the program...
}
您可以决定是否报告与 dup2()
失败或 close()
失败相关的错误。除了报告问题并退出之外,在这两种情况下您都无能为力。除非有人通过不向程序提供标准输入、标准输出和标准错误(或程序中的其他地方关闭了任何标准通道)而使您的程序受到残酷和不寻常的惩罚,否则管道和文件描述符不能标准 I/O 描述符,因此关闭是安全的。如果您不确定您的用户有多恶心,您可以保护关闭:
if (p[0] > FILENO_STDERR)
close(p[0]);
这通常是不必要的偏执(但尝试缺少标准的程序可能会很有趣 I/O)。
我正在创建一个 C 程序,并使用它在单独的分叉进程之间设置管道以进行进程间通信。
第一个进程已将我需要的数据写入管道。 但是,随着第二个进程从管道读取,我试图执行该进程以成为 UNIX 排序命令。我想以某种方式对管道中的数据调用排序。
如何在管道上调用排序?在命令行上,我可以通过提供要排序的文件名作为命令行参数进行排序,例如"sort -r MyFileToSort"。我知道管道本质上被认为是文件,但它们仅由文件描述符描述,据我所知,sort 不知道如何处理 fd。
感谢任何 help/feedback
在这种情况下,您根本不需要传递 sort
任何参数来指定输入源或输出接收器。相反,在 exec
ing 它之前,您应该根据需要将管道的文件描述符附加到其标准输入(FD 0,如果从管道接收数据)或标准输出(FD 1,如果将数据写入管道)。
请参阅 dup2()
调用,它允许您为此目的设置要将 FD 复制到的目标。正如@JonathanLeffler 指出的那样,您需要确保在调用 exec 之前关闭原始 FD(在将它们复制到您想要的数字之后)。
由于您在评论中阐明了您的目标是写入文件,因此您可以在调用 exec
之前将 FD 1 附加到该目标文件,并将 FD 0 附加到包含输入的管道。
int p[2];
if (pipe(p) != 0) ...report error and do not continue...
pid_t pid = fork();
if (pid < 0) ...report error, close pipe descriptors, and do not continue...
if (pid == 0)
{
/* Child - becomes sort */
dup2(p[0], 0);
close(p[0]);
close(p[1]);
int fd = open("output-file", O_CREAT | O_EXCL | O_WRONLY, 0644);
if (fd < 0) ...report error and exit...
dup2(fd, 1);
close(fd);
execlp("sort", "sort", (char *)0);
...report error and exit...
}
else
{
/* Parent - writes data to sort */
close(fd[0]);
...write data to fd[1]...
close(fd[1]);
int status;
int corpse;
while ((corpse = wait(&status)) > 0 && corpse != pid)
...consider reporting which child died...
...consider reporting sort status...
...continue with the rest of the program...
}
您可以决定是否报告与 dup2()
失败或 close()
失败相关的错误。除了报告问题并退出之外,在这两种情况下您都无能为力。除非有人通过不向程序提供标准输入、标准输出和标准错误(或程序中的其他地方关闭了任何标准通道)而使您的程序受到残酷和不寻常的惩罚,否则管道和文件描述符不能标准 I/O 描述符,因此关闭是安全的。如果您不确定您的用户有多恶心,您可以保护关闭:
if (p[0] > FILENO_STDERR)
close(p[0]);
这通常是不必要的偏执(但尝试缺少标准的程序可能会很有趣 I/O)。