单个管道入口可以查看整个管道吗?

单个管道入口可以查看整个管道吗?

我有一个func可以生成表格输出或 json 输出的tion。我知道处理这个问题的传统方法是使用如下参数:

$ func -j | jq .firstField
$ func -t | awk '{print $1}'

我想“展望未来”并根据管道的下一阶段推断输出类型。理想的用法很简单:

$ func | jq .firstField
$ func | awk '{print $1}'

我想象在 func 中的某个地方,我会检查管道中下一阶段的第 0 个参数,看看它是否包含j.如果是的话我会生成 json,否则生成表。

bash 允许这样的巫术吗?如果是这样,怎么办?

答案1

没有与管道关联的正式元数据或查询 API,除了可以通过流程工具从流程树中挽救的内容或通过挖掘/proc类型文件系统(如果存在)之外的内容。父 shell(可能)在内存中的某个地方拥有完整的管道,并且知道所涉及的各种子进程,尽管同样没有 API 可以让任意一个cat(毫无意义,除了作为示例)管道cat | cat | cat | ...知道它cat在哪个子进程中。管道以及其同行是谁。

% cat | cat -b | cat -e | cat -n

更有用,因为使用独特的标志,人们可以更轻松地分辨哪个是哪个;pstree(1)例如在另一个终端中可能会显示

 |     \-+= 35276 jhqdoe -zsh (zsh)
 |       |--- 44661 jhqdoe cat -n
 |       |--- 03968 jhqdoe cat -b
 |       |--- 96165 jhqdoe cat -e
 |       \--= 26975 jhqdoe cat

但这并不会告诉我们cat -e管道到cat -n,只是告诉我们 bag of cats 都属于父 shell 35276 的进程组。

% ps ao ppid,pid,command | grep '[ ]cat'
35276 44661 cat -n
35276 96165 cat -e
35276  3968 cat -b
35276 26975 cat

如果您所在的系统具有/proc或命令来检查 pid 的哪些管道或描述符连接到什么,您可能能够弄清楚什么连接到进程所属的进程组中的什么。例如,在 Linux 上lsof运行一个类似的 cat 管道,可以链接cat -ecat -n命令,因为它们共享管道 14301040:

-bash-4.2$ lsof -p 23591 | grep pipe
cat     23591 jhqdoe    0r  FIFO    0,9       0t0 14301039 pipe
cat     23591 jhqdoe    1w  FIFO    0,9       0t0 14301040 pipe
-bash-4.2$ lsof -p 23592 | grep pipe
cat     23592 jhqdoe    0r  FIFO    0,9       0t0 14301040 pipe

因此,虽然这些信息可能是可用的,但可能需要进行大量挖掘并使用不可移植的工具进行重建才能弄清楚。

父 shell 或许可以提供一种在输入管道后重写管道的方法,尽管 ZSH 挂钩函数preexec似乎没有提供任何重写要运行的命令的方法。 (这样的功能可能类似于 LISP 宏让程序员重新编写代码的方式。)父 shell 还可能提供某种 API 子进程可用于检查管道...但是需要编写这些类型的添加内容进入外壳。

然而,我们可以构建一个复杂的管道:

func | ( cd ... && ... | ( ... | awk ... ) )

在这种情况下,您func要么无法找到awk并做出错误的反应,要么您的流程管道搜索功能需要递归遍历下一个管道元素的所有命令,在这种情况下,可能awkfunc飞。或者您可能会忘记您设置了此行为,并且awk可能会被错误地修改,这可能会导致难以发现的错误......

答案2

我已经能够做到这一点,至少在Linux上是这样。这是一个演示它的脚本:https://gist.github.com/MatrixManAtYrService/790a4a058bc841b0ceb2eb0263fb5d88

用法示例:

❯ cat -b | ./luigi | jq .
[
  {
    "pid": "20832",
    "name": "cat -b",
    "node": {
      "write": "5157339",
      "read": null
    }
  },
  {
    "pid": "20833",
    "name": "bash ./luigi",
    "node": {
      "write": "5157341",
      "read": "5157339"
    }
  },
  {
    "pid": "20834",
    "name": "jq .",
    "node": {
      "write": null,
      "read": "5157341"
    }
  }
]

相关内容