Beefy Boxes and Bandwidth Generously Provided by pair Networks
Syntactic Confectionery Delight
 
PerlMonks  

Modification of a read-only value

by Sprad (Hermit)
on Aug 21, 2004 at 15:25 UTC ( [id://384799]=perlquestion: print w/replies, xml ) Need Help??

Sprad has asked for the wisdom of the Perl Monks concerning the following question:

I have a short function that takes a shell command, opens a pipe to it, and prints the output to both the screen and a log file (like tee). It works fine in most cases, but on occasion, I get the error "Modification of a read-only value attempted...".

Here's the code:

open(PIPE, "$CommandToExecute|"); while (<PIPE>) { # <--- This is the line that the error points to print LOG $_; print $_; }

I'm not sure what might be causing this error when I'm just reading a pipe. Like I said, this doesn't happen every time, just occasionally. What can I look for?

---
A fair fight is a sign of poor planning.

Replies are listed 'Best First'.
Re: Modification of a read-only value
by Aristotle (Chancellor) on Aug 21, 2004 at 15:40 UTC

    I am guessing that this code is inside a subroutine and you're calling it while $_ is aliased to a constant. Try this:

    for ( "read", "only", "value" ) { print "$_\n"; $_ = "test"; # blows up }

    The problem is probably concealed in your code like so:

    sub foo { $_ = "test"; } foo(); # works for ( "read", "only", "value" ) { print "$_\n"; foo(); # blows up }

    The solution is to put a local $_; at some opportune point to decouple one piece of the code from the other. The trap is that aliasing constructs like for(), map and friends do not need such treatment, but while(<FH>) does.

    Makeshifts last the longest.

      Yes! This was the problem. I'm not sure how far back I'm picking up constant values, but I changed the "while (<PIPE>)" to "while ($foo = <PIPE>)" and that took care of it. Thank you!

      I didn't realize that whiles treated $_ differently. I'll watch that in the future...

      ---
      A fair fight is a sign of poor planning.

        :)

        I first saw this in a question in the monastery a long time ago. That was a far nastier case, though: someone was getting spurious action at a distance. Turns out one of his map blocks was calling a sub containing a while(<FH>), and because map aliases $_, the function modified the values in his source array. Ouch.

        Ever since, while(<FH>) used without a local has been a red flag in my mind. Always localize $_ when you use this construct. (Or use a different variable, as you did, of course.)

        Makeshifts last the longest.

        while (<PIPE>)
        is equivalent to
        while (defined($_ = <PIPE>))
        so you might want to use
        while (defined($foo = <PIPE>))
        instead of
        while ($foo = <PIPE>)
        What you are using will stop when you don't expect it (such as when you read in a blank line).
Re: Modification of a read-only value
by tachyon (Chancellor) on Aug 21, 2004 at 15:38 UTC

    I doubt that the error points to that line ( but as Aristotle points out I am wrong :-( ) Perl's error messages are on occasion out by a line or two. I highly recommend checking the return value of your opens ie:

    open(PIPE, "$CommandToExecute|") or die "Can't get pipe open to $Comma +ndToExecute: $!\n";

    cheers

    tachyon

      Sound advice, but unrelated to the problem. That omission would yield an intermittent readline() on closed filehandle, not the error the OP is seeing.

      Makeshifts last the longest.

        I read your reply below. It is an error I have never encountered myself but it does look like the issue:

        for ( qw( This is new to me ) ) { print "$_\n"; open(PIPE, "dir|") or die $!; while (<PIPE>) { # <--- This is the line that the error points to print $_; } } __DATA__ This Modification of a read-only value attempted at script line 4.

        Learn something every day. Thanks!

        cheers

        tachyon

Re: Modification of a read-only value
by ysth (Canon) on Aug 22, 2004 at 04:29 UTC
    There are problems with localizing $_ if the current value is tied. You should use local *_ instead, at least until my $_ is available. Obviously within the scope of *_ you won't have access to @_, &_, or %_, so make sure you e.g. copy your subroutine parameters before the local. The special _ filehandle for filetests does still work after the local, though.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://384799]
Approved by chromatic
Front-paged by chromatic
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others taking refuge in the Monastery: (3)
As of 2025-05-22 06:48 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found

    Notices?
    erzuuliAnonymous Monks are no longer allowed to use Super Search, due to an excessive use of this resource by robots.