如何使两个命令依次使用来自 stdin 的输入?

如何使两个命令依次使用来自 stdin 的输入?

以下 perl 脚本consume-10-lines-and-exit从 stdin 读取十行并打印它们。之后它退出。

#!/usr/bin/env perl
use strict;
use warnings FATAL => 'all';

for (my $i = 0; $i < 10; $i++) {
    my $line = <STDIN>;
    print $line;
}

我试图以这样的方式组合consume-10-lines-and-exit和 ,cat即前十行输入和 被第一个命令消耗和打印,然后其余的被 消耗cat

下面的代码片段全部打印 1 到 10,而不是像我预期的那样打印 1 到 13。

printf '1 2 3 4 5 6 7 8 9 10 11 12 13' \
    | tr ' ' '\n' | { perl consume-10-lines-and-exit; cat; }

printf '1 2 3 4 5 6 7 8 9 10 11 12 13' \
    | tr ' ' '\n' | ( perl consume-10-lines-and-exit; cat )

printf '1 2 3 4 5 6 7 8 9 10 11 12 13' \
    | tr ' ' '\n' | sh -c 'perl consume-10-lines-and-exit; cat'

是否有一种对命令进行排序的结构,以便它们将从 stdin 读取输入直到退出,然后下一个命令将从上一个命令停止的地方继续?

答案1

您的问题是 perl 正在使用缓冲输入,因此提前读取超出您想要使用的行。尝试这个逐字节版本:

perl -e '
use strict;
use warnings FATAL => "all";
for (my $i = 0; $i < 10; $i++) {
  my $line;
  while(sysread(*STDIN,my $char,1)==1){
      $line .= $char;
      last if $char eq "\n";
  }
  print $line;
}'

答案2

使用分组命令适合完成这项工作,但罪魁祸首是您输入分组命令的输入,该输入是不可查找的。

POSIX 中定义INPUT FILE部分:

当标准实用程序读取可查找输入文件并在到达文件末尾之前无错误地终止时,该实用程序应确保打开的文件描述中的文件偏移量正确定位在该实用程序处理的最后一个字节之后。对于不可查找的文件,该文件的打开文件描述中的文件偏移量状态未指定

perl不是标准实用程序,但它很有可能遵循标准规范。如果你让你的文件可搜索,那么它将起作用:

$ seq 13 > /tmp/test
$ {perl -e 'for($i=0;$i<10;$i++){$line = <STDIN>;print $line}'; cat;} </tmp/test
1
2
3
4
5
6
7
8
9
10
11
12
13

如果你不想使用可查找文件,你可以强制perl使用下层调用系统调用函数read(), write(),lseek()进行 IO:

$ seq 13 | {
  PERLIO=:unix perl -e 'for($i=0;$i<10;$i++){$line = <STDIN>;print $line}'
  cat
}

答案3

也可以通过摆弄来禁用缓冲PerlIO层(另见佩尔伦)。此外,那种笨拙且冗长的 C 风格循环可以更轻松地写为... for 1..10for my $i (1..10) { ... }

$ perl -E 'say for 1..12' \
| ( PERLIO=:unix perl -e 'print "perl " . scalar <STDIN> for 1..10'; cat )
perl 1
perl 2
perl 3
perl 4
perl 5
perl 6
perl 7
perl 8
perl 9
perl 10
11
12
$ 

相关内容