首页 > 解决方案 > 将 STDIN 保存到 Perl 中的文件?

问题描述

我正在尝试使用 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

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

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

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

标签: fileperlpipebufferstdin

解决方案


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

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 中读取,以上所有方法都可以这样做。只需提供要从中读取的文件的名称作为后续参数。您甚至可以提供多个名称。


推荐阅读