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
    • 最新
    • 标签
主页 / computer / 问题 / 1882461
Accepted
pravi
pravi
Asked: 2025-02-24 00:03:41 +0800 CST2025-02-24 00:03:41 +0800 CST 2025-02-24 00:03:41 +0800 CST

这个标准输入运算符(0<)在 Linux 中如何工作?

  • 772

假设 Linux 中有两个文件。FileA和FileB都包含一些不同的水果列表。我应用以下命令。

diff fileA fileB > file.diff

接下来,我执行以下命令

patch fileA 0< file.diff

上述命令根据file.diff给出的输入修补(更正)原始文件(fileA ) ,并将输出发送到fileA(这是我的理解,我可能错了)。换句话说,fileA和fileB匹配。

据我所知,“0<” 是标准输入的重定向符号。现在,由于标准输入是键盘,patch 命令不应该从键盘读取而不是从file.diff读取吗?上述命令如何工作?

linux
  • 4 4 个回答
  • 2001 Views

4 个回答

  • Voted
  1. Best Answer
    David Anderson
    2025-02-24T00:43:21+08:002025-02-24T00:43:21+08:00

    该答案是使用 Bash shell 测试的。

    以下命令相同。1是默认值,因此可以省略。 基本上, 的标准输出diff从屏幕重定向到文件file.diff。

    diff fileA fileB > file.diff
    diff fileA fileB 1> file.diff
    

    以下命令相同。0是默认值,因此可以省略。基本上,标准输入patch从键盘重定向到文件file.diff。

    patch fileA 0< file.diff
    patch fileA < file.diff
    

    我将尝试通过以下内容进行解释。当我输入命令时tty,我得到以下输出。

    /dev/pts/0
    

    这意味着终端窗口已被分配文件名/dev/pts/0。标准输入和标准输出分别被分配文件名/dev/fd/0和/dev/fd/1。

    下面的命令测试标准输入 ( /dev/fd/0) 和终端窗口 ( /dev/pts/0) 是否具有相同的设备和 inode 值。换句话说,测试它们是否相同。在本例中,输出为true。

    if [[ /dev/fd/0 -ef /dev/pts/0 ]]; then echo "true"; else echo "false"; fi
    

    以下命令测试标准输入 ( /dev/fd/0) 和文件是否file.diff具有相同的设备和 inode 值。在这种情况下,输出为false。

    if [[ /dev/fd/0 -ef file.diff ]]; then echo "true"; else echo "false"; fi
    

    但是,如果标准输入被重定向为来自文件file.diff,如下所示,那么输出它true。

    if [[ /dev/fd/0 -ef file.diff ]]; then echo "true"; else echo "false"; fi < file.diff
    

    到目前为止,我的回答已经解释了使用 Bash shell 时重定向的行为。此行为在所有操作系统上都应该一致。我避免了实现细节,因为这在不同的操作系统上可能会有所不同。您可能对一些实现细节感兴趣,因此我针对 Ubuntu Linux 介绍了以下内容。

    下面的输出显示标准输入(/dev/fd/0)和标准输出(/dev/fd/1)是终端窗口(/dev/pts/0)的符号链接。

    无重定向

    以下是将标准输入重定向到文件 时的结果file.diff。现在,标准输入 ( /dev/fd/0) 已更改为文件 的符号链接file.diff。

    重定向

    • 10
  2. grawity
    2025-02-24T01:58:38+08:002025-02-24T01:58:38+08:00

    “0<” 是标准输入的重定向符号(据我所知)。现在,由于标准输入是键盘,patch 命令不应该从键盘读取而不是从 file.diff 读取吗?上述命令如何工作?

    不是。标准输入连接到键盘(或者更准确地说,连接到操作系统提供键盘输入的“tty”设备)。在任何时候,都可以关闭连接并在其位置打开其他东西 - 术语“标准输入”指的是特定的连接“槽”,而不是它去往的地方。(这就是为什么它被称为“标准输入”而不是“键盘输入”。)

    这些数字不仅仅是 shell 语法;它们表示程序本身如何处理打开的文件。在每个进程中,每个“打开的文件”都由一个数字(文件描述符,或 Windows 所称的句柄)表示,并且所有读/写调用都基于该数字。按照标准惯例,无论哪个打开的文件被分配了文件描述符,0它都是“标准输入”。

    如果您从终端启动程序,则终端的“tty”将预先打开为 FD 0- 或者更确切地说,从已经打开的 shell继承1- 因此是程序的标准输入。(标准输出和2标准错误也是如此。)然后“diff”程序本身将需要打开一些文件,因此它将调用open("fileA", ...),并且 fileA 将作为 FD 打开3,依此类推。

    但是就像程序可以关闭它自己打开的任何文件一样(例如,它可以通过执行来关闭文件A close(3)),它也可以执行close(0)来关闭其标准输入并在其位置打开其他文件;只要新打开的文件接收文件描述符,0根据定义它就是“标准输入”。

    shell 可以在启动程序之前执行相同的操作。使用<file.diff或0<file.diff意味着 shell 将关闭其原始 stdin 文件描述符,close(0)并将文件open("file.diff")作为新 FD打开0,然后该文件将成为新的 stdin,由“diff”程序继承。(这发生在 shell 为启动“diff”而创建的子进程中,而不会影响主 shell 进程。)现在,当 diff 调用时,read(0, …)它将从文件中读取。


    附注:

    通常open()使用最低可用的文件描述符,例如,如果 0 刚刚关闭,则下一个打开的文件将再次为 0。如果需要更精确的控制,dup2()可用于选择特定的 FD。

    可以重定向任何文件描述符,例如,5>file.txt将为程序提供一个5与该文件相对应的预打开的 FD,但这仅在程序期望接收一个 FD 时才有用;否则它将保持打开状态但未被使用。(某些程序有可用于传递其他 FD 的选项gpg --status-fd=。)

    Windows 具有类似的概念,其 cmd.exe 甚至具有相同的2>语法,但 Windows 文件句柄实际上不是从 0 开始编号的(它们是内存指针),因此 cmd.exe 仅实现 0/1/2 并将它们转换为 Windows 样式的标准句柄。(而 PowerShell 则是它自己的奇怪世界。)


    与 David Anderson 给出的示例类似,ls -l /proc/self/fd仅在 Linux 上,可用于检查其自己的文件描述符,或ls -l /proc/<pid>/fd用于任何其他进程。例如:

    $ ls -l /proc/self/fd 
    total 0
    lrwx------ 1  users 64 Feb 24 14:38 0 -> /dev/pts/4
    lrwx------ 1  users 64 Feb 24 14:38 1 -> /dev/pts/4
    lrwx------ 1  users 64 Feb 24 14:38 2 -> /dev/pts/4
    lr-x------ 1  users 64 Feb 24 14:38 3 -> /proc/833587/fd/
    

    这里文件描述符 0 (stdin)、1 (stdout)、2 (stderr) 当前连接到终端(全部从 shell 继承),而 3 由 'ls' 本身打开,当然是列出的目录。如果使用 重定向 stdin <,则会得到:

    $ ls -l /proc/self/fd < ~/test.c
    total 0
    lr-x------ 1  users 64 Feb 24 14:39 0 -> /home/grawity/test.c
    lrwx------ 1  users 64 Feb 24 14:39 1 -> /dev/pts/4
    lrwx------ 1  users 64 Feb 24 14:39 2 -> /dev/pts/4
    lr-x------ 1  users 64 Feb 24 14:39 3 -> /proc/833693/fd/
    

    给程序提供了几个无用的文件描述符也是一样:

    $ ls -l /proc/self/fd 5< ~/test.c 9> /dev/null
    total 0
    lrwx------ 1  users 64 Feb 24 14:41 0 -> /dev/pts/4
    lrwx------ 1  users 64 Feb 24 14:41 1 -> /dev/pts/4
    lrwx------ 1  users 64 Feb 24 14:41 2 -> /dev/pts/4
    lr-x------ 1  users 64 Feb 24 14:41 3 -> /proc/833741/fd/
    lr-x------ 1  users 64 Feb 24 14:41 5 -> /home/grawity/test.c
    l-wx------ 1  users 64 Feb 24 14:41 9 -> /dev/null
    
    • 9
  3. Jasen
    2025-02-24T12:47:55+08:002025-02-24T12:47:55+08:00

    在 Linux 和其他类 Unix 操作系统中

    当 shell 想要运行另一个程序时,它会通过调用 来克隆自己的副本fork()(这看起来似乎很繁重,但通过写时复制的魔力,工作量和资源成本大大降低)。然后,该副本通过调用 将其自身替换为想要运行的程序exec()(实际的 OS 调用是execve())

    在需要输入或输出重定向的情况下,分叉的副本知道这个,并且这些文件或流在fork()和之间打开exec(),因此原始 shell 保留与原始 I/O 设备的连接,但启动新程序的环境已经改变。

    这在LPG中有详细解释

    • 4
  4. Falco
    2025-02-24T17:40:40+08:002025-02-24T17:40:40+08:00

    “重定向”这个术语可能有点令人困惑,重定向的是进程的读取调用,因为读取文件描述符(如 STDIN)是拉取而不是推送。进程从“STDIN”拉取数据。

    通常,您有一个连接,将 STDIN 连接到您的键盘。您在键盘上输入的所有内容都将保存在缓冲区中,当进程从“STDIN”读取时,它将从该缓冲区读取并获取您输入的键。

    Process --read-> STDIN --read-> Keyboard-Buffer

    当您使用此命令启动进程时,proc 0< file.diff会将进程的读取调用重定向到 file.diff 的 STDIN。现在有一个从 STDIN 到 file.diff 的连接,而不是键盘。

    Process --read-> STDIN --read-> file.diff

    该过程仍然可以通过访问类似的内容(取决于终端)直接从键盘缓冲区读取/dev/pts/0,但是读取 STDIN 的调用现在将从 file.diff 读取。

    • 0

相关问题

  • 如何让我的 Linux 机器看起来像是在运行 Windows?

  • 对于 cp 或 mv,是否有等同于 cd - 的东西?

  • 以 root 身份运行 docker 容器

  • 如何在域和 Linux 活动目录中启用指纹传感器

  • 如何在CentOS 7 中将Ctrl+C 永久更改为Ctrl+K?

Sidebar

Stats

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

    如何减少“vmmem”进程的消耗?

    • 11 个回答
  • Marko Smith

    从 Microsoft Stream 下载视频

    • 4 个回答
  • Marko Smith

    Google Chrome DevTools 无法解析 SourceMap:chrome-extension

    • 6 个回答
  • Marko Smith

    Windows 照片查看器因为内存不足而无法运行?

    • 5 个回答
  • Marko Smith

    支持结束后如何激活 WindowsXP?

    • 6 个回答
  • Marko Smith

    远程桌面间歇性冻结

    • 7 个回答
  • Marko Smith

    子网掩码 /32 是什么意思?

    • 6 个回答
  • Marko Smith

    鼠标指针在 Windows 中按下的箭头键上移动?

    • 1 个回答
  • Marko Smith

    VirtualBox 无法以 VERR_NEM_VM_CREATE_FAILED 启动

    • 8 个回答
  • Marko Smith

    应用程序不会出现在 MacBook 的摄像头和麦克风隐私设置中

    • 5 个回答
  • Martin Hope
    Vickel Firefox 不再允许粘贴到 WhatsApp 网页中? 2023-08-18 05:04:35 +0800 CST
  • Martin Hope
    Saaru Lindestøkke 为什么使用 Python 的 tar 库时 tar.xz 文件比 macOS tar 小 15 倍? 2021-03-14 09:37:48 +0800 CST
  • Martin Hope
    CiaranWelsh 如何减少“vmmem”进程的消耗? 2020-06-10 02:06:58 +0800 CST
  • Martin Hope
    Jim Windows 10 搜索未加载,显示空白窗口 2020-02-06 03:28:26 +0800 CST
  • Martin Hope
    andre_ss6 远程桌面间歇性冻结 2019-09-11 12:56:40 +0800 CST
  • Martin Hope
    Riley Carney 为什么在 URL 后面加一个点会删除登录信息? 2019-08-06 10:59:24 +0800 CST
  • Martin Hope
    zdimension 鼠标指针在 Windows 中按下的箭头键上移动? 2019-08-04 06:39:57 +0800 CST
  • Martin Hope
    jonsca 我所有的 Firefox 附加组件突然被禁用了,我该如何重新启用它们? 2019-05-04 17:58:52 +0800 CST
  • Martin Hope
    MCK 是否可以使用文本创建二维码? 2019-04-02 06:32:14 +0800 CST
  • Martin Hope
    SoniEx2 更改 git init 默认分支名称 2019-04-01 06:16:56 +0800 CST

热门标签

windows-10 linux windows microsoft-excel networking ubuntu worksheet-function bash command-line hard-drive

Explore

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

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve