Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Locked thread
Mario Incandenza
Aug 24, 2000

Tell me, small fry, have you ever heard of the golden Triumph Forks?
It's also a handy idiom if you want to merge two hashes:
code:
  my (%left, %right);
  @left{keys %right} = values %right;

Adbot
ADBOT LOVES YOU

Fenderbender
Oct 10, 2003

You have the right to remain silent.

atomicstack posted:

It's also a handy idiom if you want to merge two hashes:
code:
  my (%left, %right);
  @left{keys %right} = values %right;

gently caress! I could've used this many times before!

leedo
Nov 28, 2000

Welp, I just got a new job doing full time perl development, so expect more embarrassing code snippets from me soon!

Triple Tech
Jul 28, 2006

So what, are you quitting to join Homo Explosion?
Congratulations. What city are you in?

leedo
Nov 28, 2000

Triple Tech posted:

Congratulations. What city are you in?

I'm in Chicago. I've actually been seeing quite a few (3-4 a month) Chicago perl jobs showing up jobs.perl.org.

Filburt Shellbach
Nov 6, 2007

Apni tackat say tujay aaj mitta juu gaa!
Found an interesting bug today at work. It would have slipped under my nose if other parts of the code had looser validation. What's the bug?

code:
my %is_special = map { $_ => 1 } qw/user project transaction/;

sub create_record {
    my $self = shift;
    my $type = shift;

    if ($is_special{$type} || ($type =~ /^(.*)s$/ && $is_special{$1})) {
        $type = $1 || $type;
        return $self->create_special_record($type, @_);
    }
    
    return $self->create_mundane_record($type, @_);
}

There Will Be Penalty
May 18, 2002

Makes a great pet!

Sartak posted:

Found an interesting bug today at work. It would have slipped under my nose if other parts of the code had looser validation. What's the bug?

code:
my %is_special = map { $_ => 1 } qw/user project transaction/;

sub create_record {
    my $self = shift;
    my $type = shift;

    if ($is_special{$type} || ($type =~ /^(.*)s$/ && $is_special{$1})) {
        $type = $1 || $type;
        return $self->create_special_record($type, @_);
    }
    
    return $self->create_mundane_record($type, @_);
}


if $is_special{$type} is true then $1 was preserved from the most recent regex match instead of being undefined or something, right?

Triple Tech
Jul 28, 2006

So what, are you quitting to join Homo Explosion?
Does the bitwise-and bind too tightly causing you to regexp bind on a "1"??

There Will Be Penalty
May 18, 2002

Makes a great pet!

Triple Tech posted:

Does the bitwise-and bind too tightly causing you to regexp bind on a "1"??

=~ binds tighter than &&. See perlop(1). And && is not a bitwise AND. :)

Triple Tech
Jul 28, 2006

So what, are you quitting to join Homo Explosion?

There Will Be Penalty posted:

And && is not a bitwise AND. :)

I like saying bitwise because it makes me feel smarter. Clearly it doesn't make me look smarter. I had the page open as I wrote that post and I still got it wrong!

Filburt Shellbach
Nov 6, 2007

Apni tackat say tujay aaj mitta juu gaa!

There Will Be Penalty posted:

if $is_special{$type} is true then $1 was preserved from the most recent regex match instead of being undefined or something, right?

That's right. The value of $1 was "1.1". Thankfully the called code threw a clear exception so I had no trouble zeroing in on this region of code. It could have easily been debugging hell if no exception were thrown or the value of $1 were a valid type. I wouldn't have given the code a second glance if I were any less sure that was the location of the bug.

Here's how I rewrote it:

code:
my %is_special = map { $_ => 1 } qw/user project transaction/;

sub create_record {
    my $self = shift;
    my $type = shift;

    # allow plurals
    my $is_special = $is_special{$type} || sub {
        (my $singular_type = $type) =~ s/s$//;
        return if !$is_special{$singular_type};
        $type = $singular_type;
    }->();

    if ($is_special) {
        return $self->create_special_record($type, @_);
    }
    
    return $self->create_mundane_record($type, @_);
}
That isn't as clear as I'd like it to be. Anyone want to take a stab at rewriting it better?

Filburt Shellbach fucked around with this message at 02:03 on Feb 3, 2009

Triple Tech
Jul 28, 2006

So what, are you quitting to join Homo Explosion?
Ugh, it's so wordy... It'd either preprocess the type, at the risk of removing the ability to parse "strings" as "strings" (as opposed to "string"). Also, instead of the sub, use a do block and remove the "singular type" concept in place of just modifying type directly.

Edit: 3) Farm out the parsing to a subroutine so that the complexity isn't subordinate to a larger workflow.

Triple Tech fucked around with this message at 02:17 on Feb 3, 2009

Erasmus Darwin
Mar 6, 2001

Sartak posted:

That isn't as clear as I'd like it to be. Anyone want to take a stab at rewriting it better?

How's this look?

code:
my %is_special = map { $_ => 1 } qw/user project transaction/;

sub create_record {
    my $self = shift;
    my $type = shift;
    my $original_type = $type;

    if (! $is_special{$type}) {
        # If it's plural, let's try operating on the non-pluralized type.
        $type =~ s/s$//;
    }

    if ($is_special{$type}) {
        return $self->create_special_record($type, @_);
    } else {   
        return $self->create_mundane_record($original_type, @_);
    }
}
In non-plural cases, this checks $is_special twice for the same value. That's not the greatest thing, but it does make the code really nice and clear. But unless unless this is being called a ridiculous number of times, the clarity far outweighs any other concerns.

Changing the last bit to an else is just cosmetic obviously, but I think it looks a bit better having the two possible returns parallel each other. That being said, I've done plenty of cases with "if (foo) { return blah; } return blahblah;", so either/or.

Edit: Crap. Nevermind. Just realized the problem with it.
Edit 2: Ok, fixed it by adding in $original_type.

Erasmus Darwin fucked around with this message at 03:48 on Feb 3, 2009

mister_gosh
May 24, 2002

I have a long line with thousands of characters. I want to find each occurrence of the string abc(\d+) and do something with it.

For example, I may have:

abc123 blah blah abc456 blah blah abc789 blah

What's the best way to attempt this?

Futile attempt:

code:
while($line =~ m/abc(\d+)/) {
  $line =~ m/abc(\d+)/;
  $thisOne = $1;

  # do something to it
  $line =~ s/abc(\d+)/ABC(\d+)/; # rename so we don't process again

}
This is terrible code. Help!

Triple Tech
Jul 28, 2006

So what, are you quitting to join Homo Explosion?
Can you elaborate on what exactly you want to do to it?

ShoulderDaemon
Oct 9, 2003
support goon fund
Taco Defender

mister_gosh posted:

I have a long line with thousands of characters. I want to find each occurrence of the string abc(\d+) and do something with it.

code:
while ( $line =~ m/abc(\d+)/g ) {
  doStuffWith( $1 );
}
Edit: If, for some ungodly reason, that renaming is actually needed:

code:
while ( $line =~ m/abc(\d+)/g ) {
  doStuffWith( $1 );
}
$line =~ s/abc(\d+)/ABC$1/g;

ShoulderDaemon fucked around with this message at 01:47 on Feb 17, 2009

mister_gosh
May 24, 2002

^^^^ Thanks!!!! vvvv

mister_gosh fucked around with this message at 02:13 on Feb 17, 2009

Filburt Shellbach
Nov 6, 2007

Apni tackat say tujay aaj mitta juu gaa!
code:
while ($line =~ m{abc(\d+)}g) {
    # process $1
}
edit: Oh I missed ShoulderDaemon's post!

Filburt Shellbach fucked around with this message at 02:11 on Feb 17, 2009

Xae
Jan 19, 2005

I'm getting a file like this
code:
123|Entry_A
123|Entry_B
123|Entry_C
321|Entry_B
432|Entry_A
432|Entry_B
I want to transform it into
code:
123|Entry_A,Entry_B,Entry_C
321|Entry_B
432|Entry_A,Entry_B
Any ideas?

Triple Tech
Jul 28, 2006

So what, are you quitting to join Homo Explosion?
Aggregate the entries into a hash, keyed by ID. The value of each key is a stack that you push new values on to. Then you render the stacks at the end with a list seperator.

Toe Rag
Aug 29, 2005

perlreftut will tell you exactly how to do this

Xae
Jan 19, 2005

Since the file comes out sorted, is there a way to do it with out a hash?

Filburt Shellbach
Nov 6, 2007

Apni tackat say tujay aaj mitta juu gaa!
You can iterate over the sorted keys of the hash (and sort each list of entries before printing).

Erasmus Darwin
Mar 6, 2001

Xae posted:

Since the file comes out sorted, is there a way to do it with out a hash?

Yes. Just keep track of what the number is for the line you're printed so you can print a new prefix or just a comma as appropriate. Something like this (untested):

code:
$hdr_num = -1;
while (<>) {
  chomp;
  if (/^(\d+)\|(.+)/) {
    if ($hdr_num == $1) {
      print ",$2";
    } else {
      if ($hdr_num != -1) {
        print "\n";
      }
      print "$1|$2";
      $hdr_num = $1;
    }
  }
}
if ($hdr_num != -1) {
  print "\n";
}

Shoes
Dec 19, 2007
I have a (dumb?) question about fork

I want to do

code:

my @list_of_potential_args

foreach( @list_of_potential_args){
    my $pid = fork();

    if( $pid = 0 ){
          # do stuff
    }
}

Will this wait for each child to complete, or run as many children in parallel as possible?

If it does wait, how do I run a whole bunch of children in parallel? I don't quite understand open as a pipe, even after reading perlipc.

rjmccall
Sep 7, 2007

no worries friend
Fun Shoe
fork() will not wait for the child to complete; for that you would want system. If you fork child processes, you should also wait for them. Note that forking an arbitrary number of child processes at once is not a good idea.

Opening a command as a pipe essentially fork/execs it with either its STDOUT piped to the opened handle or the opened handle piped to its STDIN; in fact, you can achieve the same effect (and more) by doing exactly that.

Shoes
Dec 19, 2007

rjmccall posted:

fork() will not wait for the child to complete; for that you would want system. If you fork child processes, you should also wait for them. Note that forking an arbitrary number of child processes at once is not a good idea.

Thanks.

Am I heading for trouble if I just try that loop, or do I somehow want to cap the number of child processes I run at a time?

rjmccall
Sep 7, 2007

no worries friend
Fun Shoe

Shoes posted:

Am I heading for trouble if I just try that loop, or do I somehow want to cap the number of child processes I run at a time?

In practice, you're probably okay if you're not forking off more than, say, ten or twenty processes. If this might be significantly higher than that, you definitely need to ration your process use.

Erasmus Darwin
Mar 6, 2001

Shoes posted:

code:
    if( $pid = 0 ){

There's a bug here. You want == rather than =. With =, you'll be assigning 0 to $pid and then your conditional will always evaluate to false. Also, make sure you've got an exit statement at the end of the code being executed by your child process, otherwise both the parent and the child process will continue forking new processes.

Shoes
Dec 19, 2007

rjmccall posted:

In practice, you're probably okay if you're not forking off more than, say, ten or twenty processes. If this might be significantly higher than that, you definitely need to ration your process use.

I'm guaranteed that this is going to be a list of a few hundred items. Is there a way to call 10 or 20 at a time?

Erasmus Darwin
Mar 6, 2001

Shoes posted:

I'm guaranteed that this is going to be a list of a few hundred items. Is there a way to call 10 or 20 at a time?

http://forums.somethingawful.com/showthread.php?threadid=2961749#post349626854

Shoes
Dec 19, 2007

Thanks a bunch.

Kidane
Dec 15, 2004

DANGER TO MANIFOLD

Shoes posted:

I'm guaranteed that this is going to be a list of a few hundred items. Is there a way to call 10 or 20 at a time?

I would suggest Parallel::ForkManager. I've used it at my job a few times because it's dead simple and Just Works.

Mithaldu
Sep 25, 2007

Let's cuddle. :3:
I'm currently working on a cross-platform gui flashcard application that i'm thinking about adding to CPAN. Flashcard sets would be stored as individual modules.

However i'm also thinking about making it possible to link the items in the flashcard sets to audio bits, which would optimally be present in the form of audiobanks available as modules on cpan. As i'm doing this with wxPerl i have one restriction though: The audio bits need to be plain wav files and actually present as files; i can't simply feed them to Wx::Sound as a variable.

Right now i'm pondering though exactly how to accomplish this. The ways i can think of would be as follows:
- Have the audiobank module be a hash which contains serialized (Storable, FreezeThaw or something like that) versions of the audio files. When the sound files are required they are unserialized, dumped with File::Temp and the filename forwarded. Problem: Not very elegant.
- Simply add the .wavs as files to the module package and figure out the path to the files, then forward that. Problem: I have no idea if there is a module for that and i don't want to do it the brute way.

Do any of you have better ideas as to how to accomplish this or other comments? Maybe i'm thinking about it in the wrong way completely?

Filburt Shellbach
Nov 6, 2007

Apni tackat say tujay aaj mitta juu gaa!
File::ShareDir and the like are useful for installing arbitrary data files in a place that your module can find them.

Mithaldu
Sep 25, 2007

Let's cuddle. :3:
Oh, that is excellent, thank you. :)

EVIL Gibson
Mar 23, 2001

Internet of Things is just someone else's computer that people can't help attaching cameras and door locks to!
:vapes:
Switchblade Switcharoo
So I want to automate typing in passwords for a ton of servers. All the servers have the same password so I can do something like ask for it once and use that one password for each system call.

There are two different commands. One is a stop and the other is a start. The start requires three different passwords for different parts of the system.

I have researched and crossed out the following solutions

1) unix expect/send - This would have been perfect, but alas it's not on the system
2) installing a perl module using cpan; more specifically the one that simulates expect. The perl modules installed are the very basic and just like #1 getting something installed on test and production is horrible

Now there are two ways I think I can do this

1) installing Expect module in a private library instead of having to call CPAN to install it. I think
2) Holy poo poo, crazy town. This one will be very tricky, but with the lack of resources, I just came up with it after looking through the commands available to me in unix. I will be forking off spawned instances of the commands and piping the command into a tee file. I will examine the output file and wait for the time it asks for a password. Now that I write about this, this is getting really convulated and I think #1 would be best.


So I just want some final thoughts for a really easy solution that I might be overlooking. I can tell you it's a SunOS system, but I cannot change for the presence or non-presence of a command.

Filburt Shellbach
Nov 6, 2007

Apni tackat say tujay aaj mitta juu gaa!
I would bundle Expect.pm and IO::Pty/IO::Tty with your script. Just stick them into lib/ and have your script use lib 'lib';

slipped
Jul 12, 2001

Xae posted:

I'm getting a file like this
code:
123|Entry_A
123|Entry_B
123|Entry_C
321|Entry_B
432|Entry_A
432|Entry_B
I want to transform it into
code:
123|Entry_A,Entry_B,Entry_C
321|Entry_B
432|Entry_A,Entry_B
Any ideas?
with respect to the thread title
code:
 $ cat dat
123|Entry_A
123|Entry_B
123|Entry_C
321|Entry_B
432|Entry_A
432|Entry_B

 $ cat dat |perl -F'\|' -anle'$h{$F[0]}.="$F[1],";END{for(sort keys%h){chop$h{$_};print"$_|$h{$_}"}}'
123|Entry_A,Entry_B,Entry_C
321|Entry_B
432|Entry_A,Entry_B

Adbot
ADBOT LOVES YOU

EVIL Gibson
Mar 23, 2001

Internet of Things is just someone else's computer that people can't help attaching cameras and door locks to!
:vapes:
Switchblade Switcharoo
I made a private lib for the above problem i have it in (my home directory)/scripts/perl_lib

The script is located in scripts

I put in use
code:
lib '(my home directory)/scripts/perl_lib'
This is where I placed Expect.pm and IO/Tty.pm and IO/Pty.pm

The library works, but one of the two IOs say that it is missing something called Constant.pm

code:
Can't locate IO/Tty/Constant.pm in @INC 
Bothered I can't find it anywhere and searching is no help (as in, I see other people having the problem but no solutions beyond 'install again' and check your folders. I know about perl and it's drat library folder system), I find a bundle of expect that also includes everything else (http://search.cpan.org/~rgiersig/Bundle-Expect-1.09/Bundle-Expect.pm). There is no other documentation so I don't know how old this version of expect is, but the module keeps returning it doesn't know methods such as 'new' or 'spawn' which I know are key parts of object oriented perl and expect respectfully.

Sartak: If you want, can I msg you and holy drat you are Sartak who I watched play nethack. Plus I saw the article you submitted on reddit today.

Let me know if you ever do a new LP so I can comment heh.

  • Locked thread