in reply to search and replace with a variable

I have this nagging, uncomfortable sense that I've not understood your question... but does this (simplified and not cargo-cult-able) code do what you intend?

#!/usr/bin/perl use strict; use warnings; use 5.016; my @lines = ("RECORDNAME foo bar baz RECORDIP 127.2.2.1 \n", "RECORDNA +ME 1 2 3 4 5 RECORDIP 127.1.1.1\n", "RECORDNAME abcd e fgh ij RECORDI +P 127.0.0.1\n"); my $fqdn = qq/www.test.sample/; my $address = qq/nowhere_ville/; say @lines; say "-" x10 . "\n"; my @newlines = ''; for $_(@lines) { $_ =~ s/RECORDNAME/$fqdn/; #no need to /ee if your vars are sca +lars $_ =~ s/RECORDIP/$address/; push(@newlines, $_); } say @newlines;
OUTPUT:
> perl 1081659.pl RECORDNAME foo bar baz RECORDIP 127.2.2.1 RECORDNAME 1 2 3 4 5 RECORDIP 127.1.1.1 RECORDNAME abcd e fgh ij RECORDIP 127.0.0.1 ---------- www.test.sample foo bar baz nowhere_ville 127.2.2.1 www.test.sample 1 2 3 4 5 nowhere_ville 127.1.1.1 www.test.sample abcd e fgh ij nowhere_ville 127.0.0.1

If not, try re-reading your node and clarify (if you can infer it) whatever confused me. And read about quotelike operators ( perlop - scroll down to "Regexp Quote-Like Operators" and "Quote-Like Operators" ) for possibly useful information.


Questions containing the words "doesn't work" (or their moral equivalent) will usually get a downvote from me unless accompanied by:
  1. code
  2. verbatim error and/or warning messages
  3. a coherent explanation of what "doesn't work actually means.

Replies are listed 'Best First'.
Re^2: search and replace with a variable
by tronmason (Initiate) on Apr 09, 2014 at 15:51 UTC
    Here's the entire code. Those values are being read in via CGI. See below. Note that defining the variables with those same values work just fine.
    #!/usr/bin/perl use strict; use CGI; use Getopt::Long; use FindBin qw($Bin $Script); my ($BASE,$NAME)=($Bin,$Script) ; my ( $fqdn, $address ); my ( @results, $result, $response ); my $sestimeout = 3600; open(FILE, "<ADDACS.csv") || die "File not found"; my @lines = <FILE>; close(FILE); my $q = CGI->new; my $fqdn = $q->param('fqdn'); chomp $fqdn; my $address = $q->param('address'); chomp $address; my @newlines; foreach(@lines) { $_ =~ s/RECORDNAME/$fqdn1/; $_ =~ s/RECORDIP/$address/; push(@newlines,$_); } open(FILE, ">ADDACS1.csv") || die "File not found"; #print "Content-type: text/plain\n\n"; print FILE @newlines; close(FILE); print "Content-type: text/plain\n\n"; print "$address / $fqdn";

      Your CGI application probably runs as some other user and group id's (not your userid). The user is dependent on the web server configuration -- possibly "nobody", or "www-...". Does the user or group that the webserver runs as have permission to write to files?

      More importantly, the code you posted won't compile because it uses strict, but never declares $fqdn1, which is the variable your substitution operator is interpolating as the substitute. You should be seeing "Global symbol "$fqdn1" requires explicit package name at XXXXXX.cgi line ...". That may show up in your server log. The server log may have other helpful information, but at minimum, the code you posted will produce that error. If the code you posted is different from the code you're running, go give yourself 30 lashes, repent, and don't do it again.

      My guess is that your actual script just doesn't have "use strict" at the top, and you added it here so we wouldn't jump on you. Because the bug you're describing, the fact that the substitution isn't replacing the match with anything, is exactly what would happen if you try to substitute $fqdn1 (which is undeclared and undefined), instead of $fqdn, which holds a parameter value. That means we're being lied to when you say "Here's the entire code." If that were the entire code, and the exact code, you would have a different set of symptoms from what you reported.

      Furthermore, the code you posted could be refined a bit, and still needs to implement flocking so that you avoid race conditions that can occur when two web hits come in within close time proximity to each other. Here is an untested example:

      use strict; use warnings; use CGI; use Getopt::Long; use FindBin; use Fcntl q(:flock); use constant FILENAME => "FindBin::Bin/file.csv"; open my $self_fh, "< $0" or die "Cannot open self: $!"; flock $self_fh, LOCK_EX or die "Cannot obtain an exclusive lock: $!"; open my $infh, '<', FILENAME or die "Unable to open input file: $!"; open my $outfh, '>', FILENAME . '.out' or die "Unable to open output f +ile: $!"; my $q = CGI->new; chomp ( my $fqdn = $q->param('fqdn') ); chomp ( my $address = $q->param('address') ); while( <$infh> ) { s/RECORDNAME/$fqdn/; s/RECORDIP/$address/; print $outfh $_; } close $infh; close $outfh or die "Failed to close output file: $!"; rename FILENAME . '.out', FILENAME or die "Unable to replace original file: $!"; close $self_fh or die $!; # Releases the lock. print "Content-type: text/plain\n\n"; print "$address / $fqdn";

      The type of locking here is "blocking". In your finished product you might instead want to use a non-blocking flock, and if a lock wasn't obtained, sleep for one second and try again. Repeat five times, and if still unsuccessful, report a useful error message and exit.


      Dave

      If you value your system, data and sanity, when you're using CGI, use -T (taint) as well. (Yes, there are exceptions, but since you're still asking us to believe in mystery source_data, this isn't one of them!)


      Questions containing the words "doesn't work" (or their moral equivalent) will usually get a downvote from me unless accompanied by:
      1. code
      2. verbatim error and/or warning messages
      3. a coherent explanation of what "doesn't work actually means.

      check Ln42!