首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为什么‘猫<(猫)’会产生EIO?

为什么‘猫<(猫)’会产生EIO?
EN

Stack Overflow用户
提问于 2017-03-17 05:35:22
回答 2查看 924关注 0票数 10

我有一个同时从两个输入文件中读取的程序。我想让这个程序从标准输入中读取。我想我应该用这样的东西:

代码语言:javascript
复制
$program1 <(cat) <($program2)

但我刚刚发现

代码语言:javascript
复制
cat <(cat)

产生

代码语言:javascript
复制
....
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

同样的,

代码语言:javascript
复制
$ cat <(read -n 1)
bash: read: read error: 0: Input/output error

所以..。Linux在syscall级别上未能实现read。这很有趣。bash不是将stdin连接到子外壳吗?:

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

编辑:

我实际上想要做的是从一个文件(另一个进程将写入该文件)读取,同时从标准输入读取,这样我就可以接受命令等等。我希望我能做到

代码语言:javascript
复制
tail -f <(od -An -vtd1 -w1) <(cat fifo)

要同时读取标准输入和FIFO,并将其放到单个标准流中,我可以通过awk (或类似的)运行。我知道我可以在任何脚本语言中轻松地解决这个问题,但是我喜欢学习如何让bash做任何事情:

编辑2:我已经要求一个新问题更全面地解释我上面描述的上下文。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2017-03-17 07:37:35

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

(我正在使用DebianLinux8.7,Bash4.4.12)

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

来自pty #1

代码语言:javascript
复制
$ echo $$
906
$ tty
/dev/pts/14
$ cat <(sleep 12345)

转到另一个pty #2

代码语言:javascript
复制
$ 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书第二版):

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

2.解释为什么cat <(cat)有时工作(不太好!)

丹尼尔·沃伊纳在一条评论中提到,cat <(cat)在OS上使用Bash 3.2.57。我刚刚成功地在Linux上用Bash 4.4.12复制了它。

来自pty #1

代码语言:javascript
复制
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

代码语言:javascript
复制
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 is 10805表示tac (PID 10805)是当前控制终端(pts/0)的前台进程组。cat (PID 10806)属于后台进程组(PGID 10803)。
  2. 但这一次,pgrp 10803不是孤立的,因为它的成员PID 10803 (bash)的父级(PID 10732bash)在另一个pgrp (PGID 10732)中,并且在同一个会话中(SID 10732)。
  3. 根据APUE书,当(非孤立的)后台进程组中的进程试图从其控制终端读取时,SIGTTIN将由终端驱动程序生成。因此,当cat读取stdin时,SIGTTIN将被发送给它,默认情况下,这个信号将停止进程。这就是为什么catSTAT列在ps输出中显示为T (已停止)。由于它停止了,我们从键盘输入的数据根本没有发送给它。所以,看起来就像,它工作了,但并不是真的。

结论:

因此,不同的行为(EIOSIGTTIN)取决于当前Bash是否是会话领导者。(在我回答的第一部分中,PID 906的bash是会话领导者,而PID 10803在第2部分的bash不是会话领导者。)

票数 12
EN

Stack Overflow用户

发布于 2019-10-10 12:56:16

接受的答案解释了为什么,但我看到一个解决办法,可以解决它。它是用更多的()炮轰它的,例如:

(cat <(cat))

请在这里找到解决方案的详细信息:https://unix.stackexchange.com/a/244333/89706

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/42849931

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档