我有一个同时从两个输入文件中读取的程序。我想让这个程序从标准输入中读取。我想我应该用这样的东西:
$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在syscall级别上未能实现read。这很有趣。bash不是将stdin连接到子外壳吗?:
有解决办法吗?我特别需要使用进程替换( ... <(...)格式),因为$program1 (顺便说一下,tail)需要文件,我需要对标准输入进行一些预处理(使用od),然后才能将它传递给tail --我不能只指定/dev/stdin等。
编辑:
我实际上想要做的是从一个文件(另一个进程将写入该文件)读取,同时从标准输入读取,这样我就可以接受命令等等。我希望我能做到
tail -f <(od -An -vtd1 -w1) <(cat fifo)要同时读取标准输入和FIFO,并将其放到单个标准流中,我可以通过awk (或类似的)运行。我知道我可以在任何脚本语言中轻松地解决这个问题,但是我喜欢学习如何让bash做任何事情:
编辑2:我已经要求一个新问题更全面地解释我上面描述的上下文。
发布于 2017-03-17 07:37:35
1.解释为什么cat <(cat)会产生EIO
(我正在使用DebianLinux8.7,Bash4.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书第二版):
TPGID is 29999表示cat (PID 29999)是当前控制终端(pts/14)的前台进程组。sleep属于后台进程组(PGID 906)。906的进程组现在是孤立的进程组,因为“每个成员的父成员本身要么是组的成员,要么不是组的会话的成员”。( PID 906的PPID是903,903在不同的会话中。)read()将与EIO一起失败。2.解释为什么cat <(cat)有时工作(不太好!)
丹尼尔·沃伊纳在一条评论中提到,cat <(cat)在OS上使用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#让我们看看发生了什么:
TPGID is 10805表示tac (PID 10805)是当前控制终端(pts/0)的前台进程组。cat (PID 10806)属于后台进程组(PGID 10803)。10803不是孤立的,因为它的成员PID 10803 (bash)的父级(PID 10732,bash)在另一个pgrp (PGID 10732)中,并且在同一个会话中(SID 10732)。SIGTTIN将由终端驱动程序生成。因此,当cat读取stdin时,SIGTTIN将被发送给它,默认情况下,这个信号将停止进程。这就是为什么cat的STAT列在ps输出中显示为T (已停止)。由于它停止了,我们从键盘输入的数据根本没有发送给它。所以,看起来就像,它工作了,但并不是真的。结论:
因此,不同的行为(EIO和SIGTTIN)取决于当前Bash是否是会话领导者。(在我回答的第一部分中,PID 906的bash是会话领导者,而PID 10803在第2部分的bash不是会话领导者。)
发布于 2019-10-10 12:56:16
接受的答案解释了为什么,但我看到一个解决办法,可以解决它。它是用更多的()炮轰它的,例如:
(cat <(cat))
请在这里找到解决方案的详细信息:https://unix.stackexchange.com/a/244333/89706
https://stackoverflow.com/questions/42849931
复制相似问题