POSIX'如何?指挥工作?

时间:2014-05-03 18:02:17

标签: shell posix tee

tee newOutputFile < existingInputFile > newOutputFile2

tee对参数的准确程度如何?会这样吗?

  1. Tee将首先处理newOutputFile < existingInputFile 因此,existingInputFile的内容将写入newOutputFile
  2. newOutputFile > newOutputFile2 因此newOutputFile的内容将写入newOutputFile 2
  3. 我正在尝试编写一个处理此特定命令的shell。但是,我对于在tee的参数中传递的顺序感到困惑。我编写程序的方式就是

    tee newOutputFile2 < existingInputFIle

1 个答案:

答案 0 :(得分:6)

tee命令是常规Unix程序,就像shsortcat一样。

处理< 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/null2>&1或类似的东西,否则通常不会修改标准错误。

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

O_IRUSR|O_IWUSR|O_IRGRP|O_IROTH

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