tee newOutputFile < existingInputFile > newOutputFile2
tee
对参数的准确程度如何?会这样吗?
newOutputFile < existingInputFile
因此,existingInputFile的内容将写入newOutputFile newOutputFile > newOutputFile2
因此newOutputFile的内容将写入newOutputFile 2 我正在尝试编写一个处理此特定命令的shell。但是,我对于在tee
的参数中传递的顺序感到困惑。我编写程序的方式就是
tee newOutputFile2 < existingInputFIle
答案 0 :(得分:6)
tee
命令是常规Unix程序,就像sh
或sort
或cat
一样。
处理< existingInputFile
和> newOutputFile2
所涉及的所有I / O重定向工作都是在调用tee
命令之前由shell完成的(在创建的fork
之后)将执行tee
命令的进程。调用该命令时,其标准输入来自existingInputFile
,其标准输出为newOutputFile2
。给tee
的唯一参数是argv[0]
(字符串tee
)和argv[1]
(字符串newOutputFile
),以及用于标记结尾的空指针参数列表。
特别注意shell不涉及existingInputFile
的实际读数;它只是打开它进行读取并将其连接到tee
的标准输入,但不知道tee
命令是否实际读取它。同样,shell不参与实际写入newOutputFile2
;它只是打开并截断它(或创建它)并将其连接到tee
的标准输出,但不知道tee
命令是否实际上向它写了任何内容。在此上下文中,tee
命令正在运行时,父shell完全被动,不执行I / O.
按照设计,tee
读取其标准输入,并将一个副本写入其参数列表中给出的每个文件,并将另一个副本写入标准输出。
我的印象是shell参与了文件的实际读写。因此,当我调用
execvp
时,它只接受命令(在本例中为tee
)和最终文件来写入内容(在本例中为newOutputFile2
)。我正在尝试创建自己的shell程序,我将如何进行I / O重定向。这是dup2
发挥作用的地方吗?
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
名称被发明之前的几年开始使用八进制权限。