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 / 问题 / 516917
Accepted
Redirect
Redirect
Asked: 2019-05-04 01:46:41 +0800 CST2019-05-04 01:46:41 +0800 CST 2019-05-04 01:46:41 +0800 CST

了解破折号中的管道和重定向

  • 772

有人问如何将两个命令的输出作为文件传递给另一个命令,他们得到了下面的答案。

( cmd1 | ( cmd2 | ( main_command /dev/fd/3 /dev/fd/4 ) 4<&0 ) 3<&0 )

我需要打开这个。

假设我有一个文本文件some_file,我希望将其作为输入传递给main_command. main_command将两个文件作为输入。如果我想与命令的输出一起使用main_command,some_file一种cmd2方法是

( cmd2 | ( main_command some_file /dev/fd/4 ) 4<&0 )
  • 这其中“最深”的部分(即一切达到高潮的地方)是 main_command some_file /dev/fd/4. 这只是将文件 some_file和/dev/fd/4作为参数传递给main_command.
  • 该4<&0部分表示stdin将指向文件描述符4。
  • cmd2 |将 的输出cmd2与后面的任何内容的输入连接起来。
  • 我真的不知道括号的功能是什么。它们只是为了解析目的而存在还是更多?

我的问题是:

  1. 如何解压问题开头的命令?
  2. 括号有什么作用?
  3. 我对更简单命令的解释是否正确?

编辑:我应该说如果我的逻辑是正确的,那么没有必要回答 1。

shell pipe
  • 1 1 个回答
  • 769 Views

1 个回答

  • Voted
  1. Best Answer
    Michael Homer
    2019-05-04T02:31:22+08:002019-05-04T02:31:22+08:00

    这是一个相当复杂的命令。我已经在最后直接回答了你的问题,但在那之前所有这一切都是在解压命令本身。我试图做到全面,所以在某些地方可能会有比你需要的更多的细节。

    括号创建一个子shell :

    ( x y z )
    

    表示从当前的 shell 派生一个新的 shell,在其中执行x y z(然后返回到当前 shell)。子外壳继承了当前外壳的所有内容,但它是一个单独的进程:这意味着它可以将输入通过管道传输到其中,并且可以在内部进行不影响父外壳的自己的环境更改。

    每个打开的文件都有一个与之关联的数字“文件描述符” 。在此上下文中的“文件”包括任何类型的输入或输出流,包括真实文件、套接字和标准 I/O 流。这些数字是句柄,可以直接与Cread函数一起使用,以识别您正在谈论的流,以及操作系统提供的相应系统调用以及所有其他 IO 函数。

    4<&0 执行重定向,将标准输入文件描述符 (0) 克隆为文件描述符 4。这意味着FD 0 被复制到 4,而不是相反。在这种情况下,它正在修改重定向之前的子 shell 的打开文件。目前,这只是为输入流创建另一个“名称”。但关键部分是这两个名称此后相互独立:FD 4 将始终引用同一个流,即使 FD 0 更改为引用其他内容并且两者不同。

    /dev/fd/4是程序访问自己打开的文件描述符的一种(非标准)方式。在 Linux 上,它是一个指向 的符号链接/proc/self/fd,它具体化了当前进程的文件描述符表。一个程序open("/dev/fd/4", O_RDONLY)可以获得一个文件句柄,该句柄引用该程序在 FD 4(例如它4自己)上的流。就程序而言,这只是一个可以像任何其他文件一样打开、关闭和读取的常规文件。因为打开的文件描述符是由子main_command进程继承的,所以文件描述符 4 与它所在的子 shell 相同,因此/dev/fd/4也可以在那里工作。

    cmd2 | x运行cmd2,并将其标准输出连接到标准输入(或 FD 0)x。在您的命令中,x是子shell 表达式。


    我们的总体指挥

    cmd2 | ( main_command /dev/fd/4 ) 4<&0
    

    然后有三个主要部分:

    1. 运行cmd2并将其输出通过管道传输到( main_command /dev/fd/4 ) 4<&0.
    2. 为由(标准输入) of4标识的流命名。0( main_command /dev/fd/4 )
    3. 作为参数运行main_command,/dev/fd/4它将(可能)作为文件打开并从中读取,得到cmd2.

    最后的效果是main_command获得一个路径名参数,它可以打开并读取cmd2from 的输出,就像 Bash 进程替换会发生的那样main_command <(cmd2):事实上,这可能会/dev/fd/63作为参数给出,否则在内部进行非常相似的处理。


    对于完整的命令

    ( cmd1 | ( cmd2 | ( main_command /dev/fd/3 /dev/fd/4 ) 4<&0 ) 3<&0 )
    

    我们有嵌套的子shell:那是因为我们想要制作标准输入的两个副本,但它是两个不同的标准输入:一个是 的输出cmd1,它在通过管道进入更大的子shell 后被放入 FD 3,另一个是输出of cmd2,在通过管道进入最里面的子壳后被放入 FD 4。这两个0s 都指标准输入,但是每个命令的标准输入是不同的,因为我们有不同的东西通过管道输入。

    我认为这是问题中最令人困惑的部分。每个命令(这里是每个子shell)都有自己的标准输入,从cmd1or管道输入cmd2,并且唯一的标准输入流被别名为3or 4。那些打开的文件描述符被下一层的子shell和子命令继承,所以/dev/fd/3在最里面的命令指的是它在外面做的同样的事情,即使标准输入现在指向别的东西。

    外括号不是严格要求的,尽管它们使某些命令更加健壮,并且可能是一个好习惯。内部是:那些用于创建一个新的子进程,该子进程可以在其中拥有自己的一组重定向,并通过管道输入自己的标准输入流。

    最里面的重定向实际上是多余的:cmd2 | main_command /dev/fd/3 /dev/stdin也可以工作,因为没有对标准输入进行进一步的更改。


    直接解决您的问题:

    1. 如何解压问题开头的命令?

      开箱是到目前为止的整个帖子。

    2. 括号有什么作用?

      括号创建一个子shell,一个独立的shell进程,可以像任何其他命令一样使用,包括将输入通过管道输入,但可以在其中执行普通的shell操作,例如重定向。

    3. 我对更简单命令的解释是否正确?

      部分。4<&0说文件描述符 4 将指向标准输入,重要的是现在称为标准输入- 而不是标准输入的概念。/dev/fd/4是“一切都是文件意义”中的“文件”,但更具体地说,它是一个路径名,当打开它时,它会将您的 FD 4 交还给您。

    • 5

相关问题

  • 有没有办法让 ls 只显示某些目录的隐藏文件?

  • grep -v grep 有什么作用

  • 为什么管道`mysql`到'tail'会改变输出格式?

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

  • `tee` 和 `bash` 进程替换顺序

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