gpt4 book ai didi

bash - 为什么 `cat <(cat)`会产生EIO?

转载 作者:行者123 更新时间:2023-11-29 08:51:34 34 4
gpt4 key购买 nike

我有一个程序可以同时读取两个输入文件。我想从标准输入中读取这个程序。我以为我会使用这样的东西:

$program1 <(cat) <($program2)

但我刚刚发现

cat <(cat)

产生

....
mmap2(NULL, 139264, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb758e000
read(0, 0xb758f000, 131072) = -1 EIO (Input/output error)
....
cat: -: Input/output error

同样,

$ cat <(read -n 1)
bash: read: read error: 0: Input/output error

所以... Linux 无法 read在系统调用级别。那很有意思。是bash没有将标准输入连接到子外壳? :(

有解决办法吗?我特别需要使用进程替换(... <(...) 格式),因为 $program1 ( tail ,顺便说一句)需要文件,我需要对标准输入进行一些预处理(使用 od ),然后才能将其传递给 tail - 我不能只指定 /dev/stdin

编辑:

我真正想做的是从文件中读取(另一个进程将写入该文件),同时我从标准输入中读取以便我可以接受命令等。我希望我能做到

tail -f <(od -An -vtd1 -w1) <(cat fifo)

同时从标准输入读取 FIFO 并将其放入单个 stdout 流中,我可以通过 awk(或类似的)运行。我知道我可以用任何脚本语言轻松解决这个问题,但我喜欢学习如何制作 bash尽一切努力:P

编辑 2:我问过 a new question这更全面地解释了我刚才描述的上下文。

最佳答案

1。解释为什么cat <(cat)生产 EIO

(我正在使用 Debian Linux 8.7、Bash 4.4.12)

让我们替换<(cat)随着长期运行<(sleep)看看发生了什么。

来自 pty #1:

$ echo $$
906
$ tty
/dev/pts/14
$ cat <(sleep 12345)

转到另一个 pty #2:

$ ps t pts/14 j
PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND
903 906 906 906 pts/14 29999 Ss 0 0:00 bash
906 29998 906 906 pts/14 29999 S 0 0:00 bash
29998 30000 906 906 pts/14 29999 S 0 0:00 sleep 12345
906 29999 29999 906 pts/14 29999 S+ 0 0:00 cat /dev/fd/63
$ ps p 903 j
PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND
1 903 903 903 ? -1 Ss 0 0:07 SCREEN -T linux -U
$

让我解释一下(根据 APUE book ,第 2 版):

  1. TPGID正在29999表示 cat (PID 29999 ) 是现在控制终端 ( pts/14 ) 的前台进程组。和 sleep在后台进程组中 (PGID 906 )。
  2. 进程组906现在是一个孤立的进程组,因为“每个成员的父进程要么本身就是该组的成员,要么不是该组 session 的成员”。 (PID 906 的 PPID 是 903903 在不同的 session 中。)
  3. 当孤立的后台进程组中的进程从其控制终端读取时,read()会失败 EIO .

2。解释为什么cat <(cat)有时有效(不是真的!)

Daniel Voina在评论中提到 cat <(cat) 可以在 OS X 上使用 Bash 3.2.57 .我刚刚设法在 Linux 上使用 Bash 重现了它 4.4.12 .

来自 pty #1:

bash-4.4# echo $$
10732
bash-4.4# tty
/dev/pts/0
bash-4.4# cat <(cat)
cat: -: Input/output error
bash-4.4#
bash-4.4#
bash-4.4# bash --norc --noprofile # start a new bash
bash-4.4# tac <(cat)
<-- It's waiting here so looks like it's working.

(第一个 cat <(cat)EIO 而失败已在我的回答的第一部分进行了解释。)

转到另一个 pty #2:

bash-4.4# ps t pts/0 j
PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND
10527 10732 10732 10732 pts/0 10805 Ss 0 0:00 bash
10732 10803 10803 10732 pts/0 10805 S 0 0:00 bash --norc --noprofile
10803 10804 10803 10732 pts/0 10805 S 0 0:00 bash --norc --noprofile
10804 10806 10803 10732 pts/0 10805 T 0 0:00 cat
10803 10805 10805 10732 pts/0 10805 S+ 0 0:00 tac /dev/fd/63
bash-4.4# ps p 10527 j
PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND
10526 10527 10527 10527 ? -1 Ss 0 0:00 SCREEN -T dtterm -U
bash-4.4#

让我们看看发生了什么:

  1. TPGID正在10805表示 tac (PID 10805 ) 是现在控制终端 ( pts/0 ) 的前台进程组。和 cat (PID 10806 ) 在后台进程组 (PGID 10803 ) 中。

  2. 但是这次 pgrp 10803不是孤立的,因为它的成员 PID 10803 ( bash ) 的父级 (PID 10732 , bash ) 在另一个 pgrp (PGID 10732 ) 中并且它在同一个 session (SID 10732 ) 中。

  3. 根据 APUE book , SIGTTIN“当(非孤立的)后台进程组中的进程试图从其控制终端读取时由终端驱动程序生成”。所以当cat读取标准输入,SIGTTIN将发送给它,默认情况下,此信号将停止该过程。这就是为什么 catSTAT列显示为 T (停止)在 ps输出。由于它已停止,我们从键盘输入的数据根本不会发送给它。所以它只是看起来有效,但实际上并非如此。

结论:

因此,不同的行为(EIOSIGTTIN)取决于当前 Bash 是否是 session 领导者。 (在我的回答的第一部分中,PID 906 的 bash 是 session 负责人,但第二部分中 PID 10803 的 bash 不是 session 负责人。)

关于bash - 为什么 `cat <(cat)`会产生EIO?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42849931/

34 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com