【问题标题】:Save STDIN to file in Perl?将 STDIN 保存到 Perl 中的文件?
【发布时间】:2021-11-11 15:41:52
【问题描述】:

我正在尝试使用 Perl 来:

  1. 等到至少 1 个字节到达 STDIN
  2. 读取所有 STDIN 并将其保存为二进制文件(与 UTF-8 兼容)

我的尝试:

# read STDIN into a string/buffer and save it (maybe this only reads one line):
echo hello | perl -e 'open (fh, ">", "my_filename.txt"); print fh <STDIN>';

# or:
echo hello | perl -e 'open STDIN, ">", "my_filename.txt"'

# ideally be able to specify the filename:
echo hello | perl -e 'open STDIN, ">", $ARGV[0]' my_filename.txt

我不能通过 echo hello &gt; my_filename.txt 使用 shell 来执行此操作,因为 shell 有一个古老的错误/功能,其中所有文件句柄都是同时打开的,而不是基于某些依赖逻辑顺序打开的。所以我的计划是等到有字节在 STDIN 上等待,然后再打开目标文件。

不幸的是,我时间紧迫,没有时间重新学习 Perl 的语法。我认为我出错的地方是我试图在这里将 STDIN 称为一个新变量,而不是实际的输入流。我查看了其他各种缓冲解决方案,但不幸的是它们在某些方面都不够用(实际上不工作,不是跨平台的,需要安装额外的可执行文件等)。

如果您直接执行重定向或通过在块上循环以减少内存使用量,则会获得奖励积分。知道如何从文件中读取和写入 STDOUT 也会有所帮助。这在 awk 之类的东西中也可能是可能的,但请注意,我正在避免使用 sed,因为 GNU sed 和 BSD sed 之间的另一种古老的语法选择很差,这通常会阻止在两个平台上使用单个命令而不进行调整。所以 Perl 似乎是要走的路。

【问题讨论】:

    标签: file perl pipe buffer stdin


    【解决方案1】:

    我不能确定,但​​我认为你想做类似的事情

    cat foo | some_operation > foo
    

    如果是这样,简单的解决方案是

    cat foo | some_operation | sponge foo
    

    但是你直接要求的可以这样实现:

    perl -e'
       @ARGV or die("usage\n");
       my $qfn = shift;
       my $line = <>;
       open(STDOUT, ">", $qfn)
          or die("open $qfn: $!\n");
       print $line;
       print while <STDIN>;
    ' file.out
    

    我们可以利用-p

    perl -pe'
       BEGIN {
          @ARGV or die("usage\n");
          $qfn = shift(@ARGV);
       }
       if ($. == 1) {
          open(STDOUT, ">", $qfn)
             or die("open $qfn: $!\n");
       }
    ' file.out
    

    我们可以输入-s

    perl -spe'
       BEGIN { defined($o) or die("usage\n"); }
       if ($. == 1) {
          open(STDOUT, ">", $o)
             or die("open $o: $!\n");
       }
    ' -- -o=file.out
    

    最后,我们可以摆脱错误检查。

    perl -spe'open(STDOUT, ">", $o) if $. == 1' -- -o=file.out
    

    奖励:如果您想从文件而不是 STDIN 读取,以上所有方法都可以这样做。只需提供要从中读取的文件的名称作为后续参数。您甚至可以提供多个名称。

    【讨论】:

    • 哇,感谢您近乎即时的回复!此命令适用于 Docker 和 Mac OS 10.15 (BSD) echo hello | perl -spe'open(STDOUT, "&gt;", $o)' -- -o=test.txt 中的 Debian 9 (GNU) 但请注意,我必须根据您的其他答案插入 --,否则会出现 Unrecognized switch: -o=test.txt 错误。我不知道是否需要包含if $. == 1 部分。另外,如果我排除 echo hello | 部分,那么它会永远等待第一个字节到达,这是正确的。
    • 添加了缺少的--。 j 测试时它就在那里,但我想我不小心删除了它
    猜你喜欢
    • 2012-12-20
    • 2013-01-17
    • 1970-01-01
    • 2012-04-27
    • 2016-12-13
    • 1970-01-01
    • 2012-04-10
    • 2022-12-05
    • 1970-01-01
    相关资源
    最近更新 更多