# Perl voodoo: $var=~s///  ?

**URL:** https://boards.straightdope.com/t/perl-voodoo-var-s/353640
**Category:** Factual Questions
**Created:** [April 21, 2006, 4:14pm UTC](https://boards.straightdope.com/t/perl-voodoo-var-s/353640 "2006-04-21T16:14:47Z")
**Posts on this page:** 11
**Page:** 1

<div class="post-metadata">

### Author: ![sciguy](https://avatars.discourse-cdn.com/v4/letter/s/e68b1a/32.png) [@sciguy](https://boards.straightdope.com/u/sciguy)
#### Post date: [April 21, 2006, 4:14pm UTC](https://boards.straightdope.com/t/perl-voodoo-var-s/353640/1 "2006-04-21T16:14:47Z")

</div>

So I’m working today, and come across a bug (?) in an old perl script I’ve been asked to maintain. The script reads data from an input file, parses data elements out of the line string, and does stuff with the parsed data. It contains the code:

```auto

foreach $line (<INPUT_FILE>) {
   chomp($line);
print "$line 
";
   **$line=~s///;**
print "$line 
";
   $line=~/^(.*)_prj.*\@(.*?)\ (.*)_/;
print "$line 
";
   $a=$1;
   $b=$2;
   $c=$3;
   # Do stuff with $a $b and $c
}

```

I’m a little confused by the bolded line (the print statements are from my debugging). It doesn’t seem to do anything the first time through the loop, but on a second iteration it strips off everything after the first “\_” character in the line (which is before the one matched by “\_prj”). That obviously leads to issues parsing $a, $b, and $c. This bug seems to have stayed hidden for a while, since the input file this script reads only has a single line 99% of the time.

My best guess is this is a bug where the previous script writer intended to strip out a Carriage Return byte, and that byte got lost in the match section during a windows-to-unix transfer. Commenting out that line makes the script work the way it’s supposed to.

But what is “=~s///” supposed to do? At first glance, it seems to be “match nothing, replace that with nothing”, a null operation. But it does _something_, and it appears to be keyed off of the pattern match of the previous iteration. If I comment out that match, then the s/// doesn’t do anything the next time through the loop.

Right now, I’m going under the assumption that the “empty” substitution isn’t needed for my script. But I’m trying to understand what that is supposed to do (if anything), or if I’ve wandered off into an “undefined behavior” area of Perl. It can be hard to tell whether weird behavior in a Perl script is by design or not. 🙂

If it matters, this script is running with perl 5.6.1 on Sun Solaris 5.8.

---

<div class="post-metadata">

### Author: ![Taran](https://avatars.discourse-cdn.com/v4/letter/t/edb3f5/32.png) [@Taran](https://boards.straightdope.com/u/Taran)
#### Post date: [April 21, 2006, 4:30pm UTC](https://boards.straightdope.com/t/perl-voodoo-var-s/353640/2 "2006-04-21T16:30:49Z")

</div>

I showed your post to the only Perl expert in arm’s reach. He made a noise best approximated as “wafuck?” and wandered away, dazed.

---

<div class="post-metadata">

### Author: ![Sage\_Rat](https://sea3.discourse-cdn.com/straightdope/user_avatar/boards.straightdope.com/sage_rat/32/399_2.png) [@Sage\_Rat](https://boards.straightdope.com/u/Sage_Rat)
#### Post date: [April 21, 2006, 4:49pm UTC](https://boards.straightdope.com/t/perl-voodoo-var-s/353640/3 "2006-04-21T16:49:41Z")

</div>

My guess would be that the original coder was called away just as he was to put something in there, then forgot what he was doing and it stayed. As to it only doing something once and only in a particular instance well…welcome to the wonderful world of interpretted languages. “Our bugs are your bugs!”

---

<div class="post-metadata">

### Author: ![carterba](https://avatars.discourse-cdn.com/v4/letter/c/85e7bf/32.png) [@carterba](https://boards.straightdope.com/u/carterba)
#### Post date: [April 21, 2006, 5:01pm UTC](https://boards.straightdope.com/t/perl-voodoo-var-s/353640/4 "2006-04-21T17:01:16Z")

</div>

I just implemented this to see what would happen. With version 5.8.5, the s/// cuts off everything before the _last_ \_. However, the regex match still works: $a, $b, and $c contain what they’re supposed to. I have no idea how that’s possible.

---

<div class="post-metadata">

### Author: ![sciguy](https://avatars.discourse-cdn.com/v4/letter/s/e68b1a/32.png) [@sciguy](https://boards.straightdope.com/u/sciguy)
#### Post date: [April 21, 2006, 6:10pm UTC](https://boards.straightdope.com/t/perl-voodoo-var-s/353640/5 "2006-04-21T18:10:33Z")

</div>

Well, thanks for the confirmation on the WTF factor of this.

I think the code I originally posted was too simplified to quite display the behavior I was seeing in the full script. The code below does recreate the weirdness:

```auto

foreach $line (<DATA>) 
{
   chomp($line);
print "line1: \"$line\"
";
   $line=~s///;
print "line2: \"$line\"
";
   $line=~/^(.*)_prj.*\@(.*?)\ (.*)_/;
print "line3: \"$line\"
";
   $cc_prj=$1;
   $pvob=$2;
   $activity=$3; 
   
   # Check for Windows style vob mount (\vobName), replace 
   # with Unix mount point (/cc/vobs/vobName)
   $pvob=~s/^\\/\/cc\/vobs\//;
   $activity=~s/\\/\/cc\/vobs\//;

   # derive the user from the deliver.username_date in the activity
   $user=$activity;
   $user=~s/deliver\.//;
   $user=~s/_.*$//;

print "cc_prj: \"$cc_prj\"
";
print "pvob: \"$pvob\"
";
print "activity: \"$activity\"
";
print "user: \"$user\"
";
print "

";
}

__DATA__
firstProject_1.0_prj_integration@\vob1_pvob deliver.user1_firstProject_1.0_prj.20060420.135133@\vob1_pvob_
secondProject_2.0_prj_integration@/cc/vobs/vob2_pvob deliver.user2_secondProject_2.0_prj.20060420.135137@/cc/vobs/vob2_pvob_

```

{if you think that data syntax looks familiar, yes I am dealing with Clearcase delivery reports}

The output I get:

```auto

line1: "firstProject_1.0_prj_integration@\vob1_pvob deliver.user1_firstProject_1.0_prj.20060420.135133@\vob1_pvob_"
line2: "firstProject_1.0_prj_integration@\vob1_pvob deliver.user1_firstProject_1.0_prj.20060420.135133@\vob1_pvob_"
line3: "firstProject_1.0_prj_integration@\vob1_pvob deliver.user1_firstProject_1.0_prj.20060420.135133@\vob1_pvob_"
cc_prj: "firstProject_1.0"
pvob: "/cc/vobs/vob1_pvob"
activity: "deliver.user1_firstProject_1.0_prj.20060420.135133@/cc/vobs/vob1_pvob"
user: "user1"
line1: "secondProject_2.0_prj_integration@/cc/vobs/vob2_pvob deliver.user2_secondProject_2.0_prj.20060420.135137@/cc/vobs/vob2_pvob_"
line2: "secondProject"
line3: "secondProject"
cc_prj: ""
pvob: ""
activity: ""
user: ""

```

Given that change required to trigger the weirdness, I suspect that the ~=s/// call re-uses the last regex string that was executed. In my case, that’s the =~s/\_.\*$// done on the $user variable in the previous loop iteration. The first time through the loop, there was no prior regex, so the ~s/// does nothing. Who knows whether that’s an intended shortcut (to apply the same regex match across multiple variables without retyping, although that seems overly obfuscated) or just an internal Perl variable not getting unset.

I agree that this was probably introduced by a “write some incomplete code, went to look something up, got distracted and forgot where I was” situation. The fixed script is up and running, now I’m just trying to figure out this weird Perl behavior.

---

<div class="post-metadata">

### Author: ![Kyrie\_Eleison](https://sea3.discourse-cdn.com/straightdope/user_avatar/boards.straightdope.com/kyrie_eleison/32/7682_2.png) [@Kyrie\_Eleison](https://boards.straightdope.com/u/Kyrie_Eleison)
#### Post date: [April 21, 2006, 6:22pm UTC](https://boards.straightdope.com/t/perl-voodoo-var-s/353640/6 "2006-04-21T18:22:54Z")

</div>

You’re right regarding what it does. And it’s intentional:

> [@Perl's Perlop Manual Page](#):
>
> ```auto
> 
> s/PATTERN/REPLACEMENT/egimosx
> ... If the pattern evaluates to the empty string, the last
> successfully executed regular expression is used instead. ...
> 
> ```

Yay, you’ve given me a new way to make my perl scripts hard to understand.

---

<div class="post-metadata">

### Author: ![sciguy](https://avatars.discourse-cdn.com/v4/letter/s/e68b1a/32.png) [@sciguy](https://boards.straightdope.com/u/sciguy)
#### Post date: [April 21, 2006, 6:49pm UTC](https://boards.straightdope.com/t/perl-voodoo-var-s/353640/7 "2006-04-21T18:49:23Z")

</div>

> [@Kyrie Eleison](#):
>
> You’re right regarding what it does. And it’s intentional:

Huh, that’s more in-depth than the perl references I was checking. That’ll teach me the error of not going straight to the source. It certainly makes sense now given what I was seeing.

> [@](#):
>
> Yay, you’ve given me a new way to make my perl scripts hard to understand.

You’re an evil, evil person. 🙂

Thanks, all, for clearing up (and sharing) one bit of confusion in my day.

---

<div class="post-metadata">

### Author: ![Voyager](https://sea3.discourse-cdn.com/straightdope/user_avatar/boards.straightdope.com/voyager/32/133_2.png) [@Voyager](https://boards.straightdope.com/u/Voyager)
#### Post date: [April 21, 2006, 7:15pm UTC](https://boards.straightdope.com/t/perl-voodoo-var-s/353640/8 "2006-04-21T19:15:14Z")

</div>

The Camel book (2nd edition) also gives the explanation Kyrie quoted (page 72 - right in the description of s/PATTERN/REPLACEMENT/

I must admit I never noticed that before…

---

<div class="post-metadata">

### Author: ![Jurph](https://avatars.discourse-cdn.com/v4/letter/j/50afbb/32.png) [@Jurph](https://boards.straightdope.com/u/Jurph)
#### Post date: [April 21, 2006, 7:50pm UTC](https://boards.straightdope.com/t/perl-voodoo-var-s/353640/9 "2006-04-21T19:50:47Z")

</div>

I picked up 3rd Edition camel, and was getting ready to crack it open, but the explanations here sound accurate and remind me of a bug I hunted down with the same origin. If you want to leave it in as a shortcut, you should put in a comment that explains that you’re modifying the variable **$\_** , Perl’s equivalent of the pronoun “that”.

You can also include a reference to [this page](http://perldoc.perl.org/perlvar.html) which explains the behavior of **$\_** - some of the nastiest bugs occur when it carries a value into a place you didn’t expect.

---

<div class="post-metadata">

### Author: ![Punoqllads](https://avatars.discourse-cdn.com/v4/letter/p/d2c977/32.png) [@Punoqllads](https://boards.straightdope.com/u/Punoqllads)
#### Post date: [April 21, 2006, 7:57pm UTC](https://boards.straightdope.com/t/perl-voodoo-var-s/353640/10 "2006-04-21T19:57:45Z")

</div>

Best. Obfuscation. Ever.

After a little bit of testing, it appears that scoping is significant. Out-of-scope regular expression matches are behaving like there is some regular expression stack.

```auto

#!/usr/bin/perl

sub wonky
{
    if ($_[0] =~ /foo/)
    {
        $_[0] =~ s/b(.)r/$1bb$1/;
    }

    $_[1] =~ s///;
}

$foo = "foobar";
$bar = "barfoo";

wonky($bar, $foo);

print "$foo, $bar
";

```

prints out

```auto

bar, abbafoo

```

Note also that it doesn’t matter which variable had the prior pattern matched against it.

---

<div class="post-metadata">

### Author: ![NoCoolUserName](https://avatars.discourse-cdn.com/v4/letter/n/5fc32e/32.png) [@NoCoolUserName](https://boards.straightdope.com/u/NoCoolUserName)
#### Post date: [April 21, 2006, 8:30pm UTC](https://boards.straightdope.com/t/perl-voodoo-var-s/353640/11 "2006-04-21T20:30:26Z")

</div>

Dropped in to give the answer, but others have done it correctly before I arrived. Let me just add:

> [@sciguy](#):
>
> …to apply the same regex match across multiple variables without retyping, although that seems overly obfuscated…

That’s the beauty of perl! 🙂 (As **Kyrie Eleison** has already enthused.)
