提问人:Chih-Hao Liu 提问时间:10/22/2023 最后编辑:Chih-Hao Liu 更新时间:10/22/2023 访问量:93
tee 命令和 tee.c 之间的区别
Difference between tee command and tee.c
问:
我目前正在 Ubuntu 20.04 Linux 上使用 C 实现“tee”命令。但是,我注意到输出略有不同。
我首先用
ls -l | tee test.txt
这是输出。
注意:这些文件来自 Linux 编程接口的在线源代码:https://man7.org/tlpi/code/online/all_files_by_chapter.html
现在,我想使用以下存储库中的代码实现“tee”命令:https://github.com/rmascarenhas/lpi/blob/master/chap04/tee.c
#define _XOPEN_SOURCE /* getopt function */
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#ifndef BUF_SIZ
#define BUF_SIZ 1024
#endif
#ifndef MAX_OUT_FILES
#define MAX_OUT_FILES 128
#endif
typedef enum { FALSE, TRUE } Bool;
void helpAndLeave(const char *progname, int status);
void failure(const char *fCall);
int
main(int argc, char *argv[]) {
int opt;
Bool append = FALSE;
int fd, flags;
int fds[MAX_OUT_FILES];
mode_t mode;
char buf[BUF_SIZ + 1];
ssize_t numRead;
int i, numFiles = 0;
/* Command line arguments parsing */
opterr = 0;
while ((opt = getopt(argc, argv, "+a")) != -1) {
switch(opt) {
case '?': helpAndLeave(argv[0], EXIT_FAILURE); break;
case 'h': helpAndLeave(argv[0], EXIT_SUCCESS); break;
case 'a': append = TRUE; break;
}
}
if (optind >= argc) {
helpAndLeave(argv[0], EXIT_FAILURE);
}
/* stdin redirection */
flags = O_CREAT | O_WRONLY;
mode = S_IRUSR | S_IWUSR; /* rw------- */
if (append) {
flags |= O_APPEND;
} else {
flags |= O_TRUNC;
}
for (i = optind; i < argc; ++i) {
fds[i - optind] = fd = open(argv[i], flags, mode);
if (fd == -1) {
failure("open");
}
++numFiles;
}
while ((numRead = read(STDIN_FILENO, buf, BUF_SIZ)) > 0) {
if (write(STDOUT_FILENO, buf, numRead) != numRead) {
failure("write");
}
for (i = 0; i < numFiles; ++i) {
if (write(fds[i], buf, numRead) != numRead) {
failure("write");
}
}
}
if (numRead == -1) {
failure("read");
}
for (i = 0; i < numFiles; ++i) {
if (close(fds[i]) == -1) {
failure("close");
}
}
return 0;
}
void
helpAndLeave(const char *progname, int status) {
fprintf(stderr, "Usage: %s [-a] <file1> <file2> ... <fileN>\n", progname);
exit(status);
}
void
failure(const char *fCall) {
perror(fCall);
exit(EXIT_FAILURE);
}
编译程序后,我用自己的 tee 程序实现
ls -l | ./tee test.txt
结果是不同的。创建“test.txt”文件并将其打印到大小为 0 字节的终端。我还参考了其他存储库并对“tee.c”程序进行了修改,但结果保持不变 - “test.txt”也出现在终端中。
因此,我想询问为什么“tee.c”程序与“tee”命令相比会产生不同的输出。
谢谢你的帮助。
答:
1赞
Nick
10/22/2023
#1
其他文件和包含在输出中的原因是:tee
test.txt
tee
是编译 tee.c 时生成的可执行文件。当您使用命令时,它会使用文件 ,因此不会出现。tee
/usr/bin/tee
- 通常,实用程序(例如)会在其中创建文件,然后将它们移动到目的地,作为终止前的最后操作。这就是为什么在使用命令时不出现它的原因。在 中,文件将基于当前目录创建,因此,如果命令参数是 just,则将在读取目录内容之前在此处创建该文件。
tee
/usr/tmp
tee
tee.c
test.txt
评论
0赞
Jonathan Leffler
10/22/2023
你能为你写信的索赔提供任何理由吗?tee
/usr/tmp
0赞
Nick
10/23/2023
@JonathanLeffler,我不能给你一本书的参考,但IIRC有一本书(大约1984年)为Unix(当时的)实用程序设定了标准。其中之一是使用 tmpfile(3) 创建输出文件,然后使用 link(2) 作为完成时的最后一个操作,将其“移动”到正确的位置,并使用 unlink(2) 删除临时目录中的条目。我认为 OP 问题的证据表明这种情况仍在继续,但我还没有查看 tee 的来源。
0赞
Jonathan Leffler
10/23/2023
我很想了解更多信息。尝试从另一个挂载的文件系统将不起作用。如今,对于单体文件系统,它不太可能成为问题,但在 1984 年,这将是一个相当大的问题。因此,代码必须在与输出文件相同的文件系统上创建临时文件,最简单的方法是在与文件相同的目录中创建临时文件。你可能会想到的一本书是 Brian W Kernighan, Rob Pike The Unix Programming Environment Nov 1983。但它没有这个规则。link()
/usr/tmp
评论
tee
ls
tee(1)
tee
ls -l | tee test.txt ; ls -l test.txt
tee