写入stdin并从stdout读取(UNIX / LINUX / C编程)

时间:2023-02-10 15:10:09

I was working on an assignment where a program took a file descriptor as an argument (generally from the parent in an exec call) and read from a file and wrote to a file descriptor, and in my testing, I realized that the program would work from the command-line and not give an error if I used 0, 1 or 2 as the file descriptor. That made sense to me except that I could write to stdin and have it show on the screen.

我正在编写一个程序,其中程序将文件描述符作为参数(通常来自exec调用中的父项)并从文件中读取并写入文件描述符,在我的测试中,我意识到程序可以正常工作从命令行开始,如果我使用0,1或2作为文件描述符,则不会出错。这对我来说很有意义,除了我可以写入stdin并让它显示在屏幕上。

Is there an explanation for this? I always thought there was some protection on stdin/stdout and you certainly can't fprintf to stdin or fgets from stdout.

对此有解释吗?我一直以为stdin / stdout上有一些保护你肯定不能从stdout到stdin或fgetsf。

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
int main()
{
    char message[20];
    read(STDOUT_FILENO, message, 20);
    write(STDIN_FILENO, message, 20);

    return 0;
}

6 个解决方案

#1


10  

Attempting to write on a file marked readonly or vice-versa would cause write and read to return -1, and fail. In this specific case, stdin and stdout are actually the same file. In essence, before your program executes (if you don't do any redirection) the shell goes:

尝试在标记为readonly的文件上写入或反之亦然会导致write和read返回-1,并且失败。在这种特定情况下,stdin和stdout实际上是同一个文件。实质上,在程序执行之前(如果你不进行任何重定向),shell会:

  if(!fork()){
       <close all fd's>
       int fd = open("/dev/tty1", O_RDWR);
       dup(fd);
       dup(fd);
       execvp("name", argv);
  }

So, stdin, out, and err are all duplicates of the same file descriptor, opened for reading and writing.

因此,stdin,out和err都是相同文件描述符的副本,为读取和写入打开。

#2


2  

read(STDIN_FILENO, message, 20); 
write(STDOUT_FILENO, message, 20);

Should work. Note - stdout my be a different place from stdin (even on the command line). You can feed output from another process as stdin into you process, or arrange the stdin/stdout to be files.

应该管用。注意 - stdout我与stdin不同(即使在命令行上)。您可以将另一个进程的输出作为stdin输入到您的进程中,或者将stdin / stdout安排为文件。

fprintf/fgets have a buffer - thus reducing the number of system calls.

fprintf / fgets有一个缓冲区 - 从而减少了系统调用的数量。

#3


1  

Best guess - stdin points to where the input is coming from, your terminal and stdout points to where output should be going, your terminal. Since they both point to the same place they are interchangeable(in this case)?

最佳猜测 - stdin指向输入的来源,终端和stdout指向输出应该到达的位置,终端。既然它们都指向同一个地方它们是可以互换的(在这种情况下)?

#4


1  

If you run a program on UNIX

如果您在UNIX上运行程序

myapp < input > output

You can open /proc/{pid}/fd/1 and read from it, open /proc/{pid}/fd/0 and write to it and for example, copy output to input. (There is possibly a simpler way to do this, but I know it works)

你可以打开/ proc / {pid} / fd / 1并从中读取,打开/ proc / {pid} / fd / 0并写入它,例如,将输出复制到输入。 (可能有一种更简单的方法可以做到这一点,但我知道它有效)

You can do any manner of things which are plain confusing if you put your mind to it. ;)

如果你把它放在心上,你可以做任何令人困惑的事情。 ;)

#5


0  

It's very possible that file descriptors 0, 1, and 2 are all open for both reading and writing (and in fact that they all refer to the same underlying "open file description"), in which case what you're doing will work. But as far as I know, there's no guarantee, so it also might not work. I do believe POSIX somewhere specifies that if stderr is connected to the terminal when a program is invoked by the shell, it's supposed to be readable and writable, but I can't find the reference right off..

文件描述符0,1和2很可能都是开放的,用于读取和写入(实际上它们都引用相同的底层“打开文件描述”),在这种情况下,您正在做的事情将起作用。但据我所知,没有保证,所以它也可能不起作用。我确实相信POSIX某处指定如果stderr在shell调用程序时连接到终端,它应该是可读写的,但是我找不到引用权。

Generally, I would recommend against ever reading from stdout or stderr unless you're looking for a terminal to read a password from, and stdin has been redirected (not a tty). And I would recommend never writing to stdin - it's dangerous and you could end up clobbering a file the user did not expect to be written to!

一般来说,我建议不要从stdout或stderr读取,除非你正在寻找一个终端来读取密码,并且stdin已被重定向(不是tty)。我建议永远不要写入stdin - 这很危险,你最终可能会破坏用户不希望被写入的文件!

#6


0  

If you want to write message into stdin, you can open current tty, and call write system call to write message into this fd:

如果要将消息写入stdin,可以打开当前tty,并调用write系统调用将消息写入此fd:

string console_cmd = "hello";
string tty = ttyname(STDIN_FILENO);
int fd = open(tty.c_str(), O_WRONLY);
write(fd, console_cmd.c_str(), console_cmd.size());

Similarly, read from stdout.

同样,从stdout读取。

#1


10  

Attempting to write on a file marked readonly or vice-versa would cause write and read to return -1, and fail. In this specific case, stdin and stdout are actually the same file. In essence, before your program executes (if you don't do any redirection) the shell goes:

尝试在标记为readonly的文件上写入或反之亦然会导致write和read返回-1,并且失败。在这种特定情况下,stdin和stdout实际上是同一个文件。实质上,在程序执行之前(如果你不进行任何重定向),shell会:

  if(!fork()){
       <close all fd's>
       int fd = open("/dev/tty1", O_RDWR);
       dup(fd);
       dup(fd);
       execvp("name", argv);
  }

So, stdin, out, and err are all duplicates of the same file descriptor, opened for reading and writing.

因此,stdin,out和err都是相同文件描述符的副本,为读取和写入打开。

#2


2  

read(STDIN_FILENO, message, 20); 
write(STDOUT_FILENO, message, 20);

Should work. Note - stdout my be a different place from stdin (even on the command line). You can feed output from another process as stdin into you process, or arrange the stdin/stdout to be files.

应该管用。注意 - stdout我与stdin不同(即使在命令行上)。您可以将另一个进程的输出作为stdin输入到您的进程中,或者将stdin / stdout安排为文件。

fprintf/fgets have a buffer - thus reducing the number of system calls.

fprintf / fgets有一个缓冲区 - 从而减少了系统调用的数量。

#3


1  

Best guess - stdin points to where the input is coming from, your terminal and stdout points to where output should be going, your terminal. Since they both point to the same place they are interchangeable(in this case)?

最佳猜测 - stdin指向输入的来源,终端和stdout指向输出应该到达的位置,终端。既然它们都指向同一个地方它们是可以互换的(在这种情况下)?

#4


1  

If you run a program on UNIX

如果您在UNIX上运行程序

myapp < input > output

You can open /proc/{pid}/fd/1 and read from it, open /proc/{pid}/fd/0 and write to it and for example, copy output to input. (There is possibly a simpler way to do this, but I know it works)

你可以打开/ proc / {pid} / fd / 1并从中读取,打开/ proc / {pid} / fd / 0并写入它,例如,将输出复制到输入。 (可能有一种更简单的方法可以做到这一点,但我知道它有效)

You can do any manner of things which are plain confusing if you put your mind to it. ;)

如果你把它放在心上,你可以做任何令人困惑的事情。 ;)

#5


0  

It's very possible that file descriptors 0, 1, and 2 are all open for both reading and writing (and in fact that they all refer to the same underlying "open file description"), in which case what you're doing will work. But as far as I know, there's no guarantee, so it also might not work. I do believe POSIX somewhere specifies that if stderr is connected to the terminal when a program is invoked by the shell, it's supposed to be readable and writable, but I can't find the reference right off..

文件描述符0,1和2很可能都是开放的,用于读取和写入(实际上它们都引用相同的底层“打开文件描述”),在这种情况下,您正在做的事情将起作用。但据我所知,没有保证,所以它也可能不起作用。我确实相信POSIX某处指定如果stderr在shell调用程序时连接到终端,它应该是可读写的,但是我找不到引用权。

Generally, I would recommend against ever reading from stdout or stderr unless you're looking for a terminal to read a password from, and stdin has been redirected (not a tty). And I would recommend never writing to stdin - it's dangerous and you could end up clobbering a file the user did not expect to be written to!

一般来说,我建议不要从stdout或stderr读取,除非你正在寻找一个终端来读取密码,并且stdin已被重定向(不是tty)。我建议永远不要写入stdin - 这很危险,你最终可能会破坏用户不希望被写入的文件!

#6


0  

If you want to write message into stdin, you can open current tty, and call write system call to write message into this fd:

如果要将消息写入stdin,可以打开当前tty,并调用write系统调用将消息写入此fd:

string console_cmd = "hello";
string tty = ttyname(STDIN_FILENO);
int fd = open(tty.c_str(), O_WRONLY);
write(fd, console_cmd.c_str(), console_cmd.size());

Similarly, read from stdout.

同样,从stdout读取。