AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / unix / 问题 / 564029
Accepted
TheMeaningfulEngineer
TheMeaningfulEngineer
Asked: 2020-01-26 03:32:27 +0800 CST2020-01-26 03:32:27 +0800 CST 2020-01-26 03:32:27 +0800 CST

什么负责将 /dev/pts/10 与 stdout/stdin/stderr 连接起来?

  • 772

tty在终端中运行命令时,它会返回/dev/pts/10.

除此之外还有文件/dev/stdout /dev/stdin和/dev/stderr. 与它们交互直接在终端中显示结果。

user@laptop:build$ tty
/dev/pts/10
user@laptop:build$ echo "Test" > /dev/stdout
Test
user@laptop:build$ echo "Test" > /dev/stdin
Test
user@laptop:build$ echo "Test" > /dev/stderr
Test

此外,从 shell 启动的任何 cli 应用程序都将为stdout/ stderr/打开文件描述符stdin。即,如果您运行打印某些内容的脚本,则打印相当于写入stdout.

到目前为止stdout//是 shell 使用的唯一接口stderr。stdin应用程序也是如此。

某些操作系统组件最终会将写入的数据移动stdout到终端,否则我将看不到任何打印的内容。

与终端之间的连接何时何地stdout/stdin/stderr发生,以便与std*终端上的某些东西进行交互?

我想挑战的粗略假设是:

/dev/stdout,/dev/stdin并且/dev/stderr是由运行的 shell 创建的,没有 shell,它们就不存在。

shell 使用代表终端 ( ) 的实际设备文件建立通信通道,并通过、和/dev/pts/10公开终端功能。这样,shell 为应用程序提供了一个简单的文件界面,而不是让每个应用程序都担心如何处理设备文件以进行简单的打印。/dev/stdout/dev/stdin/dev/stderr

更新

即使/dev/pts/10是伪终端,我也会更重视在不引入伪终端概念的情况下能够给出答案的答案。我从一个角度来看,它只会分散问题的答案:

与终端之间的连接何时何地stdout/stdin/stderr发生,以便与/dev/std*终端上的某些东西进行交互?

linux shell
  • 3 3 个回答
  • 1848 Views

3 个回答

  • Voted
  1. Piotr P. Karwasz
    2020-01-26T12:20:54+08:002020-01-26T12:20:54+08:00

    /dev/pts/10是伪终端设备对的从端。另一端是打开主克隆设备/dev/ptmx并/dev/pts/10作为对接收的程序(每次打开/dev/ptmx,您都会获得不同的从设备)。/dev/ptmx和之间的连接/dev/pts/10基本上是一个带有扭曲的双向管道。

    当您打开终端仿真器应用程序时:

    • 它打开/dev/ptmx并获取另一端的名称。它配置另一端并打开它,
    • 它分叉,
    • 新进程打开伪终端设备的另一端并将其stdin、stdout和stderr连接到它,
    • 新进程执行 shell。

    shell 没有设置这三个文件描述符,它从其父进程继承它们。与其子代从 shell 继承文件描述符的方式相同。

    备注:在 Linux 系统/dev/stdin上,/dev/stdout和/dev/stderr是真实文件,通过一系列符号链接指向/proc/<pid>/0,/proc/<pid>/1和/proc/<pid>/2,然后又指向真实的输入/输出设备:在您的情况下/dev/pts/10.

    这三个标准流的存在由 C 库保证。

    编辑:为了解决您更新的问题,让我们澄清一下答案的一些要点:

    • 写入的所有/proc/pts/*内容都由创建并显示的终端读取,读取的所有内容/proc/pts/*都来自连接到终端的输入设备,
    • 在 Linux/dev/stdout上往往是一个符号链接到/proc/self/fd/1,而/dev/stdin一个符号链接到/proc/self/fd/0. 虚拟/proc文件系统会小心地向每个应用程序显示/proc/self一个指向 的符号链接/proc/<pid>,其中<pid>是应用程序进程 ID。
    • 符号链接/proc/<pid>/fd指向应用程序打开的或从其父级继承的文件、管道和其他内容。每个应用程序都保证打开三个文件描述符:0读取输入、1写入输出、2写入错误。在您的情况下,它是/dev/pts/10.

    如果您不将输出重定向到另一个文件,则 shell 运行的每个命令都会写入终端。此规则的例外情况是,如果您的命令的进程组与终端的前台进程组不同,则写入将失败并被SIGTTOU发送到命令。可以使用stty tostop和控制此行为stty -tostop:

    stty tostop
    echo "/dev/stdout points to the terminal, but I won't print anything" &
    stty -tostop
    echo "You can see me" &
    
    • 5
  2. Best Answer
    telcoM
    2020-02-03T05:52:55+08:002020-02-03T05:52:55+08:00

    一个 POSIX 兼容的程序可以期望从其父进程继承文件描述符 #0、#1 和 #2(也分别通过编程常量和) stdin,处于已打开、准备好使用的状态。stdoutstderr

    在最简单的情况下,对于在文本控制台上登录的会话中的命令行程序,在没有应用重定向的情况下,这个继承链一直追溯到getty为登录会话初始化 TTY 设备的过程。

    使用 GUI 登录时,显示管理器进程gdm/kdm/sddm/lightdm/xdm/<whatever>dm(在会话中,或者作为桌面环境的一部分,或者使用桌面菜单或图标开始。/dev/null$HOME/.xsession-errors

    例如,对于 SSH 会话,sshd用于初始化会话的进程会分配一个伪 TTY 设备对,将stdin/out/err文件描述符指向其中的一半,然后exec()编辑用户的 shell。该分支的另一端将保留伪 TTY 设备对的另一半,并将处理网络和伪 TTY 设备之间的传出/传入流量的加密/解密,直到会话结束。

    当终端模拟器在 GUI 会话中启动时,它的行为与初始化新会话时的进程基本相同sshd:它分配一个伪 TTY,fork()s 本身,一个副本设置会话,包括指向文件描述符 #0, #1 和 #2 到伪 TTY,最后exec()是用户的 shell,而 fork 的另一端将继续处理实际维护终端窗口的可视化表示的任务。

    因此,简而言之,(伪?)TTY 设备通过初始化终端会话的东西连接到 stdin/stdout/stderr,并且可能在它和您的应用程序之间的所有进程都简单地将它们传递给一个链继承,对那些文件描述符什么都不做,只是让它们按原样传递给它们的子进程。

    当在 shell 命令行中使用重定向操作符时,作为 shellfork()自身的临时副本,为实际exec()执行命令做准备,fork()临时副本之后将关闭相应的文件描述符,在其位置打开重定向操作符指定的东西,然后exec()是命令,以便它将继承修改后的 stdin/out/err 文件描述符。


    在某些 Unix 风格的系统中/dev/std*,设备可能由 shell 处理。但是 Linux 让它们更加“真实”。

    在 Linux 中/dev/stdin,/dev/stdout和/dev/stderr只是指向/proc文件系统的普通旧符号链接:

    $ ls -l /dev/std*
    lrwxrwxrwx 1 root root 15 Feb  4 08:22 /dev/stderr -> /proc/self/fd/2
    lrwxrwxrwx 1 root root 15 Feb  4 08:22 /dev/stdin -> /proc/self/fd/0
    lrwxrwxrwx 1 root root 15 Feb  4 08:22 /dev/stdout -> /proc/self/fd/1
    

    这些链接是在系统启动时初始化udev基于 RAM 的文件系统时创建的。/dev它们只是普通的普通符号链接,没有什么神奇之处。

    But/proc是一个完全虚拟的文件系统,它实时反映系统中进程的状态,因此它有几个“神奇”的属性:

    • /proc/self是一个符号链接,指向查看它的进程/proc/<PID>的目录:
    $ ls -l /proc/self   # the PID of this ls command will be 10839
    lrwxrwxrwx 1 root root 0 Feb  4 08:22 /proc/self -> 10839/
    
    $ ls -l /proc/self   # the PID of this ls command will be 10843
    lrwxrwxrwx 1 root root 0 Feb  4 08:22 /proc/self -> 10843/
    
    • /proc/<PID>/fd是一个包含符号链接的目录,其名称对应于进程打开的文件描述符<PID>,并指向与该文件描述符关联的任何内容。

    因此,当一个进程/dev/pts/10尝试访问/dev/stdin时,符号链接将其指向/proc/self/fd/0......当/proc/self/fd/0被访问时,/proc文件系统驱动程序查看内核的进程表,使用它来查找正在访问它的进程的文件描述符表, 并显示/proc/self/fd/0为/dev/pts/10...的符号链接,正是因为该进程当前/dev/pts/10与其文件描述符 #0 相关联。

    在 Solaris 11 上,这些/dev/std*设备是指向目录的符号链接/dev/fd/,这同样是“神奇的”:

    $ uname -sr
    SunOS 5.11
    $ ls -l /dev/std*
    lrwxrwxrwx   1 root     root           0 Jun 17  2019 /dev/stderr -> ./fd/2
    lrwxrwxrwx   1 root     root           0 Jun 17  2019 /dev/stdin -> ./fd/0
    lrwxrwxrwx   1 root     root           0 Jun 17  2019 /dev/stdout -> ./fd/1
    

    在这里,Solaris/dev文件系统驱动程序使用目录中的设备节点来实现魔术,而不是像 Linux 出于历史原因那样/dev/fd重定向到文件系统。/proc

    • 2
  3. ctrl-alt-delor
    2020-02-03T04:49:27+08:002020-02-03T04:49:27+08:00

    在 shell 中运行命令

    当命令在 shell 中运行时,就会发生这种情况。

    • shell 调用fork:shell 如何在两个进程中运行。
    • 新外壳设置std in/out/err:但如果没有重定向,它什么也不做。新进程从原始 shell 继承了这些,并且 shell 已经具有正确的值。
    • 新的 shell 调用exec来运行一个新程序:这个新程序将继承 的值std in/out/err,并替换新的 shell。

    这个新的 shell 非常短暂(现在在文档中提到,因为它只是一个实现细节)。它与子外壳不同。

    新命令打开/dev/stdin

    当新程序打开/dev/stdin时,内核中的文件系统代码看到这是一个符号链接,/proc/self/fd/0然后看到这/dev/self是一个符号链接,/proc/nnnn其中 nnnn 是进程的 pid,所以 this 指向/proc/nnnn/fd/0which 指向文件,例如/dev/pts/10. 打开/dev/stdin将创建一个新的文件描述符。不需要正常打开dev/stdin,因为文件描述符 0 已经指向该文件。

    (只有当程序不是为了读取标准输入而编写的,而是可以从文件中读取时,您才需要这样做。)(所有这些对于 stdout 和 stderr 也是如此。)

    中的文件/proc不是真实文件(未存储在任何地方);这些是由文件系统在访问(从不写入磁盘)时动态创建的,该文件系统从内核中的数据结构(而不​​是磁盘)中查找数据。

    • 0

相关问题

  • grep -v grep 有什么作用

  • 需要一些系统调用

  • astyle 不会更改源文件格式

  • 如何将带有〜的路径保存到变量中?

  • 通过标签将根文件系统传递给linux内核

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    模块 i915 可能缺少固件 /lib/firmware/i915/*

    • 3 个回答
  • Marko Smith

    无法获取 jessie backports 存储库

    • 4 个回答
  • Marko Smith

    如何将 GPG 私钥和公钥导出到文件

    • 4 个回答
  • Marko Smith

    我们如何运行存储在变量中的命令?

    • 5 个回答
  • Marko Smith

    如何配置 systemd-resolved 和 systemd-networkd 以使用本地 DNS 服务器来解析本地域和远程 DNS 服务器来解析远程域?

    • 3 个回答
  • Marko Smith

    dist-upgrade 后 Kali Linux 中的 apt-get update 错误 [重复]

    • 2 个回答
  • Marko Smith

    如何从 systemctl 服务日志中查看最新的 x 行

    • 5 个回答
  • Marko Smith

    Nano - 跳转到文件末尾

    • 8 个回答
  • Marko Smith

    grub 错误:你需要先加载内核

    • 4 个回答
  • Marko Smith

    如何下载软件包而不是使用 apt-get 命令安装它?

    • 7 个回答
  • Martin Hope
    user12345 无法获取 jessie backports 存储库 2019-03-27 04:39:28 +0800 CST
  • Martin Hope
    Carl 为什么大多数 systemd 示例都包含 WantedBy=multi-user.target? 2019-03-15 11:49:25 +0800 CST
  • Martin Hope
    rocky 如何将 GPG 私钥和公钥导出到文件 2018-11-16 05:36:15 +0800 CST
  • Martin Hope
    Evan Carroll systemctl 状态显示:“状态:降级” 2018-06-03 18:48:17 +0800 CST
  • Martin Hope
    Tim 我们如何运行存储在变量中的命令? 2018-05-21 04:46:29 +0800 CST
  • Martin Hope
    Ankur S 为什么 /dev/null 是一个文件?为什么它的功能不作为一个简单的程序来实现? 2018-04-17 07:28:04 +0800 CST
  • Martin Hope
    user3191334 如何从 systemctl 服务日志中查看最新的 x 行 2018-02-07 00:14:16 +0800 CST
  • Martin Hope
    Marko Pacak Nano - 跳转到文件末尾 2018-02-01 01:53:03 +0800 CST
  • Martin Hope
    Kidburla 为什么真假这么大? 2018-01-26 12:14:47 +0800 CST
  • Martin Hope
    Christos Baziotis 在一个巨大的(70GB)、一行、文本文件中替换字符串 2017-12-30 06:58:33 +0800 CST

热门标签

linux bash debian shell-script text-processing ubuntu centos shell awk ssh

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve