Why do I need list context when writing unix command output to a file in Perl?

StackOverflow https://stackoverflow.com/questions/21364724

  •  02-10-2022
  •  | 
  •  

Domanda

I'm trying to output the output from a unix command to a file handle (which goes to an output file). Initially my code was like this:

open (OUT,'>',$out)|| die "cannot open $out";
my $file =`cut -f $list $in`;
print OUT $file;
close OUT;

It gave me a "segmentation fault" error message, which is pretty rare for a perl script... I searched around and make one small change below in the second and third line by changing the output into an array @file instead of variable $file and somehow, for whatever reason, it worked!

open (OUT,'>',$out)|| die "cannot open $out";
my @file =`cut -f $list $in`;
print OUT @file;
close OUT;

Does anyone understand why it worked and what is the difference between outputting into array vs a scalar?

È stato utile?

Soluzione 3

qx/readpipe/backticks in scalar context will try to load the external command's output into a single scalar variable. In list context, the output is loaded into a list of several scalars.

If the external command's output is extraordinarily long, Perl might choke on trying to cram it into a single string, but not have a problem creating several small strings and loading them to an array.

Altri suggerimenti

I ran a quick test of your initial program:

#! /usr/bin/env perl
#
use strict;
use feature qw(say);
use warnings;

my $out = "test.out";
my $list = "2";
my $in = "test.txt";
open OUT,'>',$out || die "cannot open $out";
my $file =`cut -f $list $in`;
print OUT $file;
close OUT;

My test file looked like this:

this    that
who     knows
who     cares
I       know

My test.out file looks like this:

that
knows
cares
know

If the test file didn't exist, the program still runs, and I get an error printed out on STDERR by cut. If I give it a bad field spec, the program still runs and I get another error printed on STDERR by cut.

I've tried a few things, but couldn't get the program to fail outright with a segmentation fault.

So, the question is what is producing that segmentation fault. Is it cut or Perl? Put a print statement after the my $file =cut -f $list $in; and the print OUT $file; lines and see if they print anything. If they do, the problem is with cut and not with Perl. If not, somehow your Perl interpreter is having problems. So, then the question is why does it work on my system and not yours:

  • What version of Perl are you using?
  • What exactly is the OS? Is this Linux, Mac OSX, Cygwin running under Windows, or some old ancient version of Solaris/SunOS?
  • Is this the entire message?
  • Was any of your $out file written?

The program you wrote should work and does on my systems. I'm using Perl 5.14 on Mac OS X 10.9 and on Perl 5.8.8 on a Linux RHEL box. I haven't tried this on Cygwin.

I can't say why it worked, but the difference between calling the backticks operator in scalar and list context is:

  • in list context, qx// will return a list of output lines split on $/ ( the input record separator) but including those line endings
  • in scalar context, it will just return a single string

Here is an example:

use strict;
use warnings;
use Data::Dump;

my $foo = `perl -e "print qq{foo\nbar baz};"`;
my @bar = `perl -e "print qq{foo\nbar baz};"`;

dd $foo;
dd @bar;

Which produces

"foo\nbar baz"
("foo\n", "bar baz")
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top