POSIX'tee'命令如何工作?

Ria*_*Ria 4 shell posix tee

tee newOutputFile < existingInputFile > newOutputFile2

究竟如何tee参与争论?会这样吗?

  1. Tee将首先进行处理newOutputFile < existingInputFile 因此,existingInputFile的内容将被写入newOutputFile
  2. newOutputFile > newOutputFile2 因此newOutputFile的内容将写入newOutputFile 2

我正在尝试编写一个处理此特定命令的shell.但是,我对于在参数中传递的顺序感到困惑tee.我编写程序的方式就可以了

tee newOutputFile2 < existingInputFIle

Jon*_*ler 6

tee命令是一个常规的Unix程序,就像shsortcat.

所有I/O重定向工作都涉及处理,< existingInputFile> newOutputFile2tee调用命令之前由shell完成(在fork创建执行tee命令的进程之后).调用该命令的标准输入来自existingInputFile和标准输出newOutputFile2.给出的唯一参数teeargv[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
Run Code Online (Sandbox Code Playgroud)

在您自己的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!
Run Code Online (Sandbox Code Playgroud)

请注意,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);
Run Code Online (Sandbox Code Playgroud)

这是因为open()返回最低可用的先前未打开的文件描述符,因此通过关闭0,您知道open()成功时将返回0,失败时返回-1(即使先前已关闭0).然后,通过归纳,您知道在关闭1后,open()成功时将返回1,失败时返回-1(即使先前已关闭1).你通常不会与标准错误修补,除非该命令行包括I/O重定向如2>/dev/null2>&1或类似的东西.

如果您愿意,可以将0644写为:

O_IRUSR|O_IWUSR|O_IRGRP|O_IROTH
Run Code Online (Sandbox Code Playgroud)

(|O_IWGRP|O_IWOTH如果你想使用组和其他写权限(0666),则添加; umask无论如何都将修改权限).就个人而言,我发现八进制文件更容易阅读,但我在O_Ixyyy名字发明之前的几年就开始使用八进制权限.