以编程方式从STDIN或Perl中的输入文件中读取


75

在Perl中以编程方式从stdin或输入文件(如果提供)中读取的最巧妙的方法是什么?

Answers:


88
while (<>) {
print;
}

将从命令行上指定的文件或如果未提供文件的stdin中读取

如果需要在命令行中进行此循环构建,则可以使用以下-n选项:

$ perl -ne 'print;'

在这里,您只需将代码{}从第一个示例放到''第二个


23
+1 + nitpick:“将从命令行中连续指定的一个或多个文件中读取”
msw

4
...而您所需要做的就是写入@ARGV = "/path/to/some/file.ext";并读取文件-因此您甚至可以在某些条件下对默认文件进行编程。
Axeman 2010年

3
如果脚本很短,则可以使用-n或-p选项进行perl,并在命令行上指定处理方式:perl -n -e '$_ = uc($_); print;' yourfile。使用-p而不是-n,perl会在末尾自动打印$ _。
mivk 2012年

3
当然,您也可以my @slurp = <>; foreach my $line (@slurp) { ... }
一口气“吞噬

您没有用类似这样的名称来命名读取行的原因while (my $line = <>) {...吗?
David Mertens

48

这提供了一个可使用的命名变量:

foreach my $line ( <STDIN> ) {
    chomp( $line );
    print "$line\n";
}

要读取文件,请像下面这样通过管道输入:

program.pl < inputfile

10
+1以避免太常见的速记不可读的Perl代码
MikeKulls 2013年

6
-1,因为foreach会处理整个文件。最好在while循环中分配给该行。此外,Perl对于裸尖括号具有内置的神奇行为,因此您应该说while(my $ line = <>)。这样就无需重定向。
David Mertens 2014年

3
第一行应显示foreach my $line ( <STDIN> ) { 我同意@MikeKulls。如果Perl脚本不可读,这不是Perl的错。程序员要怪这里!
tiktak 2014年

1
重新读取问题后,此响应是不正确的,因为它仅从标准输入中读取,而不读取命令行上指定的文件。ennuikiller的答案是正确的,尽管我将其写为while(my $line = <>) { print $line; }
MikeKulls 2014年

2
@MikeKulls是不是应该这样,while (my $line = <>, defined $line) { ... }还是while (<>) { my $line = $_; }要避免停在空白行?
格雷戈里·尼斯贝

15

在某些情况下,“最流畅”的方法是利用-n切换。它使用while(<>)循环隐式地包装代码,并灵活地处理输入。

slickestWay.pl

#!/ usr / bin / perl -n

开始: {
  #在这里做一次
}

#为单行输入实现逻辑
打印$ result;

在命令行中:

chmod +x slickestWay.pl

现在,根据您的输入执行以下操作之一:

  1. 等待用户输入

    ./slickestWay.pl
    
  2. 从参数中命名的文件中读取(无需重定向)

    ./slickestWay.pl input.txt
    ./slickestWay.pl input.txt moreInput.txt
    
  3. 使用管道

    someOtherScript | ./slickestWay.pl 
    

BEGIN如果需要初始化某种面向对象的接口,例如Text :: CSV或类似的东西,可以使用将该块添加到shebang中,则该块是必需的-M

-l并且-p也是你的朋友。


13

您需要使用<>运算符:

while (<>) {
    print $_; # or simply "print;"
}

可以压缩为:

print while (<>);

任意文件:

open F, "<file.txt" or die $!;
while (<F>) {
    print $_;
}
close F;

9

如果有原因不能使用上述ennuikiller提供的简单解决方案,则必须使用Typeglobs来操纵文件句柄。这是更多工作的方式。本示例将文件从中复制$ARGV[0]到中$ARGV[1]。如果未指定文件,则默认分别为STDINSTDOUT

use English;

my $in;
my $out;

if ($#ARGV >= 0){
    unless (open($in,  "<", $ARGV[0])){
      die "could not open $ARGV[0] for reading.";
    }
}
else {
    $in  = *STDIN;
}

if ($#ARGV >= 1){
    unless (open($out, ">", $ARGV[1])){
      die "could not open $ARGV[1] for writing.";
    }
}
else {
    $out  = *STDOUT;
}

while ($_ = <$in>){
    $out->print($_);
}

+1是一种方法,如果命令行上提供要读取的文件名,而是其他地方(在某个变量中,从配置文件中读取等-您只需将其替换$ARGV[0]为其他变量)在其他所有答案均失败的情况下可以使用...
Matija Nalis

或者,为了读取,只需unshift将文件名放到@ARGV并使用菱形运算符即可<>
David Mertens


0

这是我制作脚本的方式,该脚本可以接受命令行输入或重定向文本文件。

if ($#ARGV < 1) {
    @ARGV = ();
    @ARGV = <>;
    chomp(@ARGV);
}


这会将文件的内容重新分配给@ARGV,从那里您就可以像对待某人包括命令行选项一样处理@ARGV。

警告

如果没有文件被重定向,则程序将处于空闲状态,因为它正在等待来自STDIN的输入。

我还没有找到一种方法来检测文件是否已被重定向,以消除STDIN问题。


这是一个很酷的方法,但不是OP所要求的。这样就可以传递单个文件名作为参数,其内容用作命令行参数。OP正在寻找与众不同的东西。另外,为什么隐晦$#ARGV < 1而不是(我认为是)更清晰@ARGV == 1
David Mertens

-2
if(my $file = shift) { # if file is specified, read from that
  open(my $fh, '<', $file) or die($!);
  while(my $line = <$fh>) {
    print $line;
  }
}
else { # otherwise, read from STDIN
  print while(<>);
}

7
普通<>运算符将自动查找和读取命令行上提供的任何文件。不需要if
戴夫·谢罗曼

您也没有描述shift此处的操作
Eugen Konkov
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.