tee newOutputFile < existingInputFile > newOutputFile2
tee
将如何接收参数?会是这样吗?
newOutputFile < existingInputFile
所以existingInputFile的内容会被写入newOutputFile newOutputFile > newOutputFile2
所以newOutputFile的内容会写入newOutputFile 2 我正在尝试编写一个处理此特定命令的 shell。但是,我对将参数传递给
tee
的顺序感到困惑。我对我的程序进行编码的方式它会做tee newOutputFile2 < existingInputFIle
最佳答案
tee
命令是一个常规的 Unix 程序,就像 sh
或 sort
或 cat
。
在调用 < existingInputFile
命令之前(在创建将执行 > newOutputFile2
命令的进程的 tee
之后),处理 fork
和 tee
所涉及的所有 I/O 重定向工作都由 shell 完成。调用该命令时,其标准输入来自 existingInputFile
,其标准输出将转到 newOutputFile2
。给 tee
的唯一参数是 argv[0]
(字符串 tee
)和 argv[1]
(字符串 newOutputFile
),加上一个空指针来标记参数列表的结尾。
特别注意,shell 不参与 existingInputFile
的实际读取;它只是打开它进行读取并将其连接到 tee
的标准输入,但不知道 tee
命令是否实际读取它。同样,shell 不参与实际写入 newOutputFile2
;它只是打开并截断它(或创建它)并将其连接到 tee
的标准输出,但不知道 tee
命令是否实际向其写入任何内容。在这种情况下,当 tee
命令正在运行时,父 shell 是完全被动的,不执行 I/O。
按照设计,tee
读取其标准输入并将所有内容的一份副本写入其参数列表中给出的每个文件,并将另一份副本写入标准输出。
shell 只参与打开和关闭文件,而不参与文件的读取和写入。在命令行 tee newOutputFile < existingInputFile > newOutputFile2
中,命令是 tee
,唯一的其他参数是 newOutputFile
。通常,命令(在本例中为 tee
)不知道为其提供标准输入的文件的名称,也不知道它在其标准输出上写入的文件的名称。实际上,尤其是使用 tee
时,输入通常是管道而不是文件,而且输出通常也是管道而不是文件:
some_command arg1 arg2 | tee some_command.log | another_command its_arg1 its_arg2 > output.file
在您自己的 shell 程序中,您可以使用
dup2()
复制您单独打开的文件描述符,使其成为标准输入:// Redirect standard input from existingInputFile using dup2()
char *i_filename = "existingInputFile";
int fd = open(i_filename, O_RDONLY);
if (fd < 0)
{
fprintf(stderr, "unable to open file %s for reading (%d: %s)\n",
i_filename, errno, strerror(errno));
exit(1);
}
dup2(fd, STDIN_FILENO);
close(fd); // Crucial!
请注意,在这种情况下关闭
fd
很重要。否则,该命令将在至少打开一个未在命令行中指定的额外文件描述符的情况下运行。您将有一个用于标准输出重定向的类似代码块。或者你可以使用:
// Redirect standard input from existingInputFile
close(0);
char *i_filename = "existingInputFile";
int fd = open(i_filename, O_RDONLY);
if (fd < 0)
{
fprintf(stderr, "unable to open file %s for reading (%d: %s)\n",
i_filename, errno, strerror(errno));
exit(1);
}
assert(fd == 0);
// Redirect standard output to NewOutputFile2
close(1);
char * o_filename = "newOutputFile2";
fd = open(o_filename, O_WRONLY|O_CREAT|O_TRUNC, 0644); // Classically 0666
if (fd < 0)
{
fprintf(stderr, "unable to open file %s for writing (%d: %s)\n",
o_filename, errno, strerror(errno));
exit(1);
}
assert(fd == 1);
这是因为
open()
返回最低可用的先前未打开的文件描述符,因此通过关闭 0,您知道 open()
将在成功时返回 0,在失败时返回 -1(即使 0 之前已关闭)。然后,通过归纳,您知道关闭 1 后,open()
将在成功时返回 1,在失败时返回 -1(即使 1 之前已关闭)。您通常不会修改标准错误,除非命令行包含 I/O 重定向,例如 2>/dev/null
或 2>&1
或类似的东西。如果您愿意,可以将 0644 写为:
O_IRUSR|O_IWUSR|O_IRGRP|O_IROTH
(如果您想使用组和其他写权限(0666),请添加
|O_IWGRP|O_IWOTH
;无论如何,umask
都会修改权限)。就个人而言,我发现八进制更容易阅读,但我在 O_Ixyyy
名称被发明之前的几年就开始使用八进制权限。关于shell - POSIX 'tee' 命令如何工作?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/23448043/